diff -Nru a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
--- a/Documentation/filesystems/Locking	Tue Apr 30 17:10:25 2002
+++ b/Documentation/filesystems/Locking	Tue Apr 30 17:10:25 2002
@@ -254,7 +254,7 @@
 llseek:		yes	(see below)
 read:		no
 write:		no
-readdir:	yes	(see below)
+readdir: 	no	
 poll:		no
 ioctl:		yes	(see below)
 mmap:		no
diff -Nru a/MAINTAINERS b/MAINTAINERS
--- a/MAINTAINERS	Tue Apr 30 17:10:23 2002
+++ b/MAINTAINERS	Tue Apr 30 17:10:23 2002
@@ -1180,6 +1180,12 @@
 L:	linux-sound@vger.kernel.org
 S:	Maintained
 
+ORINOCO DRIVER
+P:	David Gibson
+M:	hermes@gibson.dropbear.id.au
+W:	http://www.ozlabs.org/people/dgibson/dldwd
+S:	Maintained
+
 PARALLEL PORT SUPPORT
 P:	Phil Blundell
 M:	Philip.Blundell@pobox.com
diff -Nru a/Makefile b/Makefile
--- a/Makefile	Tue Apr 30 17:10:23 2002
+++ b/Makefile	Tue Apr 30 17:10:23 2002
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 5
-SUBLEVEL = 11
+SUBLEVEL = 12
 EXTRAVERSION =
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
diff -Nru a/arch/alpha/defconfig b/arch/alpha/defconfig
--- a/arch/alpha/defconfig	Tue Apr 30 17:10:25 2002
+++ b/arch/alpha/defconfig	Tue Apr 30 17:10:25 2002
@@ -252,7 +252,6 @@
 CONFIG_IDEDMA_PCI_AUTO=y
 # CONFIG_IDEDMA_ONLYDISK is not set
 CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_PCI_WIP is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
diff -Nru a/arch/alpha/mm/init.c b/arch/alpha/mm/init.c
--- a/arch/alpha/mm/init.c	Tue Apr 30 17:10:25 2002
+++ b/arch/alpha/mm/init.c	Tue Apr 30 17:10:25 2002
@@ -139,7 +139,7 @@
 	printk("%ld reserved pages\n",reserved);
 	printk("%ld pages shared\n",shared);
 	printk("%ld pages swap cached\n",cached);
-	show_buffers();
+	printk("%ld buffermem pages\n", nr_buffermem_pages());
 }
 #endif
 
diff -Nru a/arch/alpha/mm/numa.c b/arch/alpha/mm/numa.c
--- a/arch/alpha/mm/numa.c	Tue Apr 30 17:10:23 2002
+++ b/arch/alpha/mm/numa.c	Tue Apr 30 17:10:23 2002
@@ -426,5 +426,5 @@
 	printk("%ld pages shared\n",shared);
 	printk("%ld pages swap cached\n",cached);
 	printk("%ld pages in page table cache\n",pgtable_cache_size);
-	show_buffers();
+	printk("%ld buffermem pages\n", nr_buffermem_pages());
 }
diff -Nru a/arch/arm/def-configs/footbridge b/arch/arm/def-configs/footbridge
--- a/arch/arm/def-configs/footbridge	Tue Apr 30 17:10:25 2002
+++ b/arch/arm/def-configs/footbridge	Tue Apr 30 17:10:25 2002
@@ -409,7 +409,6 @@
 CONFIG_BLK_DEV_OFFBOARD=y
 CONFIG_IDEDMA_PCI_AUTO=y
 CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_PCI_WIP is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
diff -Nru a/arch/arm/def-configs/iq80310 b/arch/arm/def-configs/iq80310
--- a/arch/arm/def-configs/iq80310	Tue Apr 30 17:10:24 2002
+++ b/arch/arm/def-configs/iq80310	Tue Apr 30 17:10:24 2002
@@ -460,7 +460,6 @@
 # CONFIG_BLK_DEV_OFFBOARD is not set
 CONFIG_IDEDMA_PCI_AUTO=y
 CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_PCI_WIP is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
diff -Nru a/arch/arm/mm/init.c b/arch/arm/mm/init.c
--- a/arch/arm/mm/init.c	Tue Apr 30 17:10:23 2002
+++ b/arch/arm/mm/init.c	Tue Apr 30 17:10:23 2002
@@ -64,18 +64,6 @@
  */
 struct page *empty_zero_page;
 
-/* This is currently broken
- * PG_skip is used on sparc/sparc64 architectures to "skip" certain
- * parts of the address space.
- *
- * #define PG_skip	10
- * #define PageSkip(page) (machine_is_riscpc() && test_bit(PG_skip, &(page)->flags))
- *			if (PageSkip(page)) {
- *				page = page->next_hash;
- *				if (page == NULL)
- *					break;
- *			}
- */
 void show_mem(void)
 {
 	int free = 0, total = 0, reserved = 0;
@@ -113,7 +101,7 @@
 	printk("%d slab pages\n", slab);
 	printk("%d pages shared\n", shared);
 	printk("%d pages swap cached\n", cached);
-	show_buffers();
+	printk("%ld buffermem pages\n", nr_buffermem_pages());
 }
 
 struct node_info {
diff -Nru a/arch/cris/drivers/ide.c b/arch/cris/drivers/ide.c
--- a/arch/cris/drivers/ide.c	Tue Apr 30 17:10:25 2002
+++ b/arch/cris/drivers/ide.c	Tue Apr 30 17:10:25 2002
@@ -687,7 +687,7 @@
 /*
  * etrax_dma_intr() is the handler for disk read/write DMA interrupts
  */
-static ide_startstop_t etrax_dma_intr (ide_drive_t *drive)
+static ide_startstop_t etrax_dma_intr (struct ata_device *drive, struct request *rq)
 {
 	int i, dma_stat;
 	byte stat;
@@ -699,11 +699,9 @@
 	stat = GET_STAT();			/* get drive status */
 	if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
 		if (!dma_stat) {
-			struct request *rq;
-			rq = HWGROUP(drive)->rq;
 			for (i = rq->nr_sectors; i > 0;) {
 				i -= rq->current_nr_sectors;
-				ide_end_request(drive, 1);
+				ide_end_request(drive, rq, 1);
 			}
 			return ide_stopped;
 		}
diff -Nru a/arch/cris/mm/init.c b/arch/cris/mm/init.c
--- a/arch/cris/mm/init.c	Tue Apr 30 17:10:25 2002
+++ b/arch/cris/mm/init.c	Tue Apr 30 17:10:25 2002
@@ -183,7 +183,7 @@
 	printk("%d pages shared\n",shared);
 	printk("%d pages swap cached\n",cached);
 	printk("%ld pages in page table cache\n",pgtable_cache_size);
-	show_buffers();
+	printk("%ld buffermem pages\n", nr_buffermem_pages());
 }
 
 /*
diff -Nru a/arch/i386/defconfig b/arch/i386/defconfig
--- a/arch/i386/defconfig	Tue Apr 30 17:10:23 2002
+++ b/arch/i386/defconfig	Tue Apr 30 17:10:23 2002
@@ -261,9 +261,6 @@
 CONFIG_IDEDMA_PCI_AUTO=y
 # CONFIG_IDEDMA_ONLYDISK is not set
 CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_BLK_DEV_IDE_TCQ is not set
-# CONFIG_BLK_DEV_IDE_TCQ_DEFAULT is not set
-# CONFIG_IDEDMA_PCI_WIP is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
@@ -314,6 +311,7 @@
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
 #
 CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_REPORT_LUNS=y
 CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOGGING is not set
 
@@ -620,6 +618,7 @@
 # PCMCIA character devices
 #
 # CONFIG_PCMCIA_SERIAL_CS is not set
+# CONFIG_SYNCLINK_CS is not set
 # CONFIG_MWAVE is not set
 
 #
@@ -791,6 +790,7 @@
 # CONFIG_SND_EMU10K1 is not set
 # CONFIG_SND_KORG1212 is not set
 # CONFIG_SND_NM256 is not set
+# CONFIG_SND_RME32 is not set
 # CONFIG_SND_RME96 is not set
 # CONFIG_SND_RME9652 is not set
 # CONFIG_SND_TRIDENT is not set
@@ -819,8 +819,9 @@
 # Miscellaneous USB options
 #
 # CONFIG_USB_DEVICEFS is not set
-# CONFIG_USB_BANDWIDTH is not set
 # CONFIG_USB_LONG_TIMEOUT is not set
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
 
 #
 # USB Host Controller Drivers
@@ -829,7 +830,6 @@
 # CONFIG_USB_OHCI_HCD is not set
 CONFIG_USB_UHCI_ALT=y
 # CONFIG_USB_OHCI is not set
-CONFIG_USB_HOST=y
 
 #
 # USB Device Class drivers
@@ -925,6 +925,8 @@
 # CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19QW is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19QI is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
 # CONFIG_USB_SERIAL_KLSI is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
@@ -942,6 +944,7 @@
 # CONFIG_USB_TIGL is not set
 # CONFIG_USB_AUERSWALD is not set
 # CONFIG_USB_RIO500 is not set
+# CONFIG_USB_BRLVGER is not set
 
 #
 # Kernel hacking
diff -Nru a/arch/i386/mm/init.c b/arch/i386/mm/init.c
--- a/arch/i386/mm/init.c	Tue Apr 30 17:10:25 2002
+++ b/arch/i386/mm/init.c	Tue Apr 30 17:10:25 2002
@@ -95,7 +95,7 @@
 	printk("%d reserved pages\n",reserved);
 	printk("%d pages shared\n",shared);
 	printk("%d pages swap cached\n",cached);
-	show_buffers();
+	printk("%ld buffermem pages\n", nr_buffermem_pages());
 }
 
 /* References to section boundaries */
diff -Nru a/arch/ia64/defconfig b/arch/ia64/defconfig
--- a/arch/ia64/defconfig	Tue Apr 30 17:10:23 2002
+++ b/arch/ia64/defconfig	Tue Apr 30 17:10:23 2002
@@ -233,7 +233,6 @@
 # CONFIG_IDEDMA_PCI_AUTO is not set
 # CONFIG_IDEDMA_ONLYDISK is not set
 CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_PCI_WIP is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
diff -Nru a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c
--- a/arch/ia64/hp/sim/simserial.c	Tue Apr 30 17:10:25 2002
+++ b/arch/ia64/hp/sim/simserial.c	Tue Apr 30 17:10:25 2002
@@ -156,7 +156,6 @@
 				continue;
 			} else if ( seen_esc == 2 ) {
 				if ( ch == 'P' ) show_state();		/* F1 key */
-				if ( ch == 'Q' ) show_buffers();	/* F2 key */
 #ifdef CONFIG_KDB
 				if ( ch == 'S' )
 					kdb(KDB_REASON_KEYBOARD, 0, (kdb_eframe_t) regs);
diff -Nru a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
--- a/arch/ia64/mm/init.c	Tue Apr 30 17:10:25 2002
+++ b/arch/ia64/mm/init.c	Tue Apr 30 17:10:25 2002
@@ -200,7 +200,7 @@
 			pgdat = pgdat->node_next;
 		} while (pgdat);
 		printk("Total of %ld pages in page table cache\n", pgtable_cache_size);
-		show_buffers();
+		printk("%ld buffermem pages\n", nr_buffermem_pages());
 		printk("%d free buffer pages\n", nr_free_buffer_pages());
 	}
 #else /* !CONFIG_DISCONTIGMEM */
@@ -220,7 +220,7 @@
 	printk("%d pages shared\n", shared);
 	printk("%d pages swap cached\n", cached);
 	printk("%ld pages in page table cache\n", pgtable_cache_size);
-	show_buffers();
+	printk("%ld buffermem pages\n", nr_buffermem_pages());
 #endif /* !CONFIG_DISCONTIGMEM */
 }
 
diff -Nru a/arch/ia64/sn/configs/sn1/defconfig-bigsur-mp b/arch/ia64/sn/configs/sn1/defconfig-bigsur-mp
--- a/arch/ia64/sn/configs/sn1/defconfig-bigsur-mp	Tue Apr 30 17:10:25 2002
+++ b/arch/ia64/sn/configs/sn1/defconfig-bigsur-mp	Tue Apr 30 17:10:25 2002
@@ -212,7 +212,6 @@
 # CONFIG_BLK_DEV_OFFBOARD is not set
 # CONFIG_IDEDMA_PCI_AUTO is not set
 CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_PCI_WIP is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
diff -Nru a/arch/ia64/sn/configs/sn1/defconfig-bigsur-sp b/arch/ia64/sn/configs/sn1/defconfig-bigsur-sp
--- a/arch/ia64/sn/configs/sn1/defconfig-bigsur-sp	Tue Apr 30 17:10:25 2002
+++ b/arch/ia64/sn/configs/sn1/defconfig-bigsur-sp	Tue Apr 30 17:10:25 2002
@@ -212,7 +212,6 @@
 # CONFIG_BLK_DEV_OFFBOARD is not set
 # CONFIG_IDEDMA_PCI_AUTO is not set
 CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_PCI_WIP is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
diff -Nru a/arch/m68k/mm/init.c b/arch/m68k/mm/init.c
--- a/arch/m68k/mm/init.c	Tue Apr 30 17:10:25 2002
+++ b/arch/m68k/mm/init.c	Tue Apr 30 17:10:25 2002
@@ -109,7 +109,7 @@
     printk("%d pages shared\n",shared);
     printk("%d pages swap cached\n",cached);
     printk("%ld pages in page table cache\n",pgtable_cache_size);
-    show_buffers();
+	printk("%ld buffermem pages\n", nr_buffermem_pages());
 }
 
 extern void init_pointer_table(unsigned long ptable);
diff -Nru a/arch/mips/defconfig-ddb5476 b/arch/mips/defconfig-ddb5476
--- a/arch/mips/defconfig-ddb5476	Tue Apr 30 17:10:25 2002
+++ b/arch/mips/defconfig-ddb5476	Tue Apr 30 17:10:25 2002
@@ -227,7 +227,6 @@
 # CONFIG_BLK_DEV_OFFBOARD is not set
 # CONFIG_IDEDMA_PCI_AUTO is not set
 # CONFIG_BLK_DEV_IDEDMA is not set
-# CONFIG_IDEDMA_PCI_WIP is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
diff -Nru a/arch/mips/defconfig-it8172 b/arch/mips/defconfig-it8172
--- a/arch/mips/defconfig-it8172	Tue Apr 30 17:10:25 2002
+++ b/arch/mips/defconfig-it8172	Tue Apr 30 17:10:25 2002
@@ -292,7 +292,6 @@
 # CONFIG_BLK_DEV_OFFBOARD is not set
 CONFIG_IDEDMA_PCI_AUTO=y
 CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_PCI_WIP is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
diff -Nru a/arch/mips/mm/init.c b/arch/mips/mm/init.c
--- a/arch/mips/mm/init.c	Tue Apr 30 17:10:25 2002
+++ b/arch/mips/mm/init.c	Tue Apr 30 17:10:25 2002
@@ -137,7 +137,7 @@
 	printk("%d pages swap cached\n",cached);
 	printk("%ld pages in page table cache\n",pgtable_cache_size);
 	printk("%d free pages\n", free);
-	show_buffers();
+	printk("%ld buffermem pages\n", nr_buffermem_pages());
 }
 
 /* References to section boundaries */
diff -Nru a/arch/mips64/mm/init.c b/arch/mips64/mm/init.c
--- a/arch/mips64/mm/init.c	Tue Apr 30 17:10:23 2002
+++ b/arch/mips64/mm/init.c	Tue Apr 30 17:10:23 2002
@@ -341,7 +341,7 @@
 	printk("%d pages swap cached\n",cached);
 	printk("%ld pages in page table cache\n", pgtable_cache_size);
 	printk("%d free pages\n", free);
-	show_buffers();
+	printk("%ld buffermem pages\n", nr_buffermem_pages());
 }
 
 #ifndef CONFIG_DISCONTIGMEM
diff -Nru a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c
--- a/arch/parisc/mm/init.c	Tue Apr 30 17:10:25 2002
+++ b/arch/parisc/mm/init.c	Tue Apr 30 17:10:25 2002
@@ -155,7 +155,7 @@
 	printk("%d reserved pages\n",reserved);
 	printk("%d pages shared\n",shared);
 	printk("%d pages swap cached\n",cached);
-	show_buffers();
+	printk("%ld buffermem pages\n", nr_buffermem_pages());
 }
 
 void set_pte_phys (unsigned long vaddr, unsigned long phys)
diff -Nru a/arch/ppc/configs/common_defconfig b/arch/ppc/configs/common_defconfig
--- a/arch/ppc/configs/common_defconfig	Tue Apr 30 17:10:25 2002
+++ b/arch/ppc/configs/common_defconfig	Tue Apr 30 17:10:25 2002
@@ -255,7 +255,6 @@
 # CONFIG_BLK_DEV_OFFBOARD is not set
 CONFIG_IDEDMA_PCI_AUTO=y
 CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_PCI_WIP is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
diff -Nru a/arch/ppc/configs/k2_defconfig b/arch/ppc/configs/k2_defconfig
--- a/arch/ppc/configs/k2_defconfig	Tue Apr 30 17:10:23 2002
+++ b/arch/ppc/configs/k2_defconfig	Tue Apr 30 17:10:23 2002
@@ -238,7 +238,6 @@
 # CONFIG_BLK_DEV_OFFBOARD is not set
 # CONFIG_IDEDMA_PCI_AUTO is not set
 CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_PCI_WIP is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
diff -Nru a/arch/ppc/configs/menf1_defconfig b/arch/ppc/configs/menf1_defconfig
--- a/arch/ppc/configs/menf1_defconfig	Tue Apr 30 17:10:23 2002
+++ b/arch/ppc/configs/menf1_defconfig	Tue Apr 30 17:10:23 2002
@@ -242,7 +242,6 @@
 # CONFIG_BLK_DEV_OFFBOARD is not set
 # CONFIG_IDEDMA_PCI_AUTO is not set
 # CONFIG_BLK_DEV_IDEDMA is not set
-# CONFIG_IDEDMA_PCI_WIP is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
diff -Nru a/arch/ppc/configs/mvme5100_defconfig b/arch/ppc/configs/mvme5100_defconfig
--- a/arch/ppc/configs/mvme5100_defconfig	Tue Apr 30 17:10:23 2002
+++ b/arch/ppc/configs/mvme5100_defconfig	Tue Apr 30 17:10:23 2002
@@ -236,7 +236,6 @@
 # CONFIG_BLK_DEV_OFFBOARD is not set
 # CONFIG_IDEDMA_PCI_AUTO is not set
 # CONFIG_BLK_DEV_IDEDMA is not set
-# CONFIG_IDEDMA_PCI_WIP is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
diff -Nru a/arch/ppc/configs/pmac_defconfig b/arch/ppc/configs/pmac_defconfig
--- a/arch/ppc/configs/pmac_defconfig	Tue Apr 30 17:10:25 2002
+++ b/arch/ppc/configs/pmac_defconfig	Tue Apr 30 17:10:25 2002
@@ -245,7 +245,6 @@
 # CONFIG_BLK_DEV_OFFBOARD is not set
 CONFIG_IDEDMA_PCI_AUTO=y
 CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_PCI_WIP is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
diff -Nru a/arch/ppc/configs/pplus_defconfig b/arch/ppc/configs/pplus_defconfig
--- a/arch/ppc/configs/pplus_defconfig	Tue Apr 30 17:10:25 2002
+++ b/arch/ppc/configs/pplus_defconfig	Tue Apr 30 17:10:25 2002
@@ -249,7 +249,6 @@
 # CONFIG_BLK_DEV_OFFBOARD is not set
 # CONFIG_IDEDMA_PCI_AUTO is not set
 CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_PCI_WIP is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
diff -Nru a/arch/ppc/configs/sandpoint_defconfig b/arch/ppc/configs/sandpoint_defconfig
--- a/arch/ppc/configs/sandpoint_defconfig	Tue Apr 30 17:10:25 2002
+++ b/arch/ppc/configs/sandpoint_defconfig	Tue Apr 30 17:10:25 2002
@@ -212,7 +212,6 @@
 # CONFIG_BLK_DEV_OFFBOARD is not set
 # CONFIG_IDEDMA_PCI_AUTO is not set
 CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_PCI_WIP is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
diff -Nru a/arch/ppc/defconfig b/arch/ppc/defconfig
--- a/arch/ppc/defconfig	Tue Apr 30 17:10:25 2002
+++ b/arch/ppc/defconfig	Tue Apr 30 17:10:25 2002
@@ -255,7 +255,6 @@
 # CONFIG_BLK_DEV_OFFBOARD is not set
 CONFIG_IDEDMA_PCI_AUTO=y
 CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_PCI_WIP is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
diff -Nru a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c
--- a/arch/ppc/mm/init.c	Tue Apr 30 17:10:25 2002
+++ b/arch/ppc/mm/init.c	Tue Apr 30 17:10:25 2002
@@ -142,7 +142,7 @@
 	printk("%d reserved pages\n",reserved);
 	printk("%d pages shared\n",shared);
 	printk("%d pages swap cached\n",cached);
-	show_buffers();
+	printk("%ld buffermem pages\n", nr_buffermem_pages());
 }
 
 void si_meminfo(struct sysinfo *val)
diff -Nru a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c
--- a/arch/ppc64/mm/init.c	Tue Apr 30 17:10:25 2002
+++ b/arch/ppc64/mm/init.c	Tue Apr 30 17:10:25 2002
@@ -138,7 +138,7 @@
 	printk("%d reserved pages\n",reserved);
 	printk("%d pages shared\n",shared);
 	printk("%d pages swap cached\n",cached);
-	show_buffers();
+	printk("%ld buffermem pages\n", nr_buffermem_pages());
 }
 
 void si_meminfo(struct sysinfo *val)
diff -Nru a/arch/s390/mm/init.c b/arch/s390/mm/init.c
--- a/arch/s390/mm/init.c	Tue Apr 30 17:10:25 2002
+++ b/arch/s390/mm/init.c	Tue Apr 30 17:10:25 2002
@@ -89,7 +89,7 @@
         printk("%d pages shared\n",shared);
         printk("%d pages swap cached\n",cached);
         printk("%ld pages in page table cache\n",pgtable_cache_size);
-        show_buffers();
+        printk("%ld buffermem pages\n", nr_buffermem_pages());
 }
 
 /* References to section boundaries */
diff -Nru a/arch/s390x/mm/init.c b/arch/s390x/mm/init.c
--- a/arch/s390x/mm/init.c	Tue Apr 30 17:10:25 2002
+++ b/arch/s390x/mm/init.c	Tue Apr 30 17:10:25 2002
@@ -89,7 +89,7 @@
         printk("%d pages shared\n",shared);
         printk("%d pages swap cached\n",cached);
         printk("%ld pages in page table cache\n",pgtable_cache_size);
-        show_buffers();
+        printk("%ld buffermem pages\n", nr_buffermem_pages());
 }
 
 /* References to section boundaries */
diff -Nru a/arch/sh/mm/init.c b/arch/sh/mm/init.c
--- a/arch/sh/mm/init.c	Tue Apr 30 17:10:25 2002
+++ b/arch/sh/mm/init.c	Tue Apr 30 17:10:25 2002
@@ -73,7 +73,7 @@
 	printk("%d reserved pages\n",reserved);
 	printk("%d pages shared\n",shared);
 	printk("%d pages swap cached\n",cached);
-	show_buffers();
+	printk("%ld buffermem pages\n", nr_buffermem_pages());
 }
 
 /* References to section boundaries */
diff -Nru a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c
--- a/arch/sparc/kernel/sys_sunos.c	Tue Apr 30 17:10:25 2002
+++ b/arch/sparc/kernel/sys_sunos.c	Tue Apr 30 17:10:25 2002
@@ -193,7 +193,7 @@
 	 * fool it, but this should catch most mistakes.
 	 */
 	freepages = atomic_read(&buffermem_pages) >> PAGE_SHIFT;
-	freepages += atomic_read(&page_cache_size);
+	freepages += get_page_cache_size();
 	freepages >>= 1;
 	freepages += nr_free_pages();
 	freepages += nr_swap_pages;
diff -Nru a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c
--- a/arch/sparc/mm/init.c	Tue Apr 30 17:10:25 2002
+++ b/arch/sparc/mm/init.c	Tue Apr 30 17:10:25 2002
@@ -84,7 +84,7 @@
 	if (sparc_cpu_model == sun4m || sparc_cpu_model == sun4d)
 		printk("%ld entries in page dir cache\n",pgd_cache_size);
 #endif	
-	show_buffers();
+	printk("%ld buffermem pages\n", nr_buffermem_pages());
 }
 
 extern pgprot_t protection_map[16];
diff -Nru a/arch/sparc64/defconfig b/arch/sparc64/defconfig
--- a/arch/sparc64/defconfig	Tue Apr 30 17:10:25 2002
+++ b/arch/sparc64/defconfig	Tue Apr 30 17:10:25 2002
@@ -289,7 +289,6 @@
 CONFIG_IDEDMA_PCI_AUTO=y
 CONFIG_IDEDMA_ONLYDISK=y
 CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_PCI_WIP is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
diff -Nru a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c
--- a/arch/sparc64/kernel/sys_sunos32.c	Tue Apr 30 17:10:25 2002
+++ b/arch/sparc64/kernel/sys_sunos32.c	Tue Apr 30 17:10:25 2002
@@ -157,7 +157,7 @@
 	 * fool it, but this should catch most mistakes.
 	 */
 	freepages = atomic_read(&buffermem_pages) >> PAGE_SHIFT;
-	freepages += atomic_read(&page_cache_size);
+	freepages += get_page_cache_size();
 	freepages >>= 1;
 	freepages += nr_free_pages();
 	freepages += nr_swap_pages;
diff -Nru a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
--- a/arch/sparc64/mm/init.c	Tue Apr 30 17:10:25 2002
+++ b/arch/sparc64/mm/init.c	Tue Apr 30 17:10:25 2002
@@ -334,7 +334,7 @@
 #ifndef CONFIG_SMP
 	printk("%d entries in page dir cache\n",pgd_cache_size);
 #endif	
-	show_buffers();
+	printk("%ld buffermem pages\n", nr_buffermem_pages());
 }
 
 void mmu_info(struct seq_file *m)
diff -Nru a/arch/x86_64/defconfig b/arch/x86_64/defconfig
--- a/arch/x86_64/defconfig	Tue Apr 30 17:10:25 2002
+++ b/arch/x86_64/defconfig	Tue Apr 30 17:10:25 2002
@@ -214,7 +214,6 @@
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_BLK_DEV_IDE_TCQ is not set
 # CONFIG_BLK_DEV_IDE_TCQ_DEFAULT is not set
-# CONFIG_IDEDMA_PCI_WIP is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
diff -Nru a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c
--- a/arch/x86_64/mm/init.c	Tue Apr 30 17:10:25 2002
+++ b/arch/x86_64/mm/init.c	Tue Apr 30 17:10:25 2002
@@ -69,7 +69,7 @@
 	printk("%d reserved pages\n",reserved);
 	printk("%d pages shared\n",shared);
 	printk("%d pages swap cached\n",cached);
-	show_buffers();
+	printk("%ld buffermem pages\n", nr_buffermem_pages());
 }
 
 /* References to section boundaries */
diff -Nru a/drivers/block/blkpg.c b/drivers/block/blkpg.c
--- a/drivers/block/blkpg.c	Tue Apr 30 17:10:23 2002
+++ b/drivers/block/blkpg.c	Tue Apr 30 17:10:23 2002
@@ -219,6 +219,7 @@
 	unsigned short usval;
 	kdev_t dev = to_kdev_t(bdev->bd_dev);
 	int holder;
+	unsigned long *ra_pages;
 
 	intval = block_ioctl(bdev, cmd, arg);
 	if (intval != -ENOTTY)
@@ -240,13 +241,21 @@
 		case BLKFRASET:
 			if(!capable(CAP_SYS_ADMIN))
 				return -EACCES;
-			return blk_set_readahead(bdev, arg);
+			ra_pages = blk_get_ra_pages(dev);
+			if (ra_pages == NULL)
+				return -ENOTTY;
+			*ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
+			return 0;
 
 		case BLKRAGET:
 		case BLKFRAGET:
 			if (!arg)
 				return -EINVAL;
-			return put_user(blk_get_readahead(bdev), (long *)arg);
+			ra_pages = blk_get_ra_pages(dev);
+			if (ra_pages == NULL)
+				return -ENOTTY;
+			return put_user((*ra_pages * PAGE_CACHE_SIZE) / 512,
+						(long *)arg);
 
 		case BLKSECTGET:
 			if ((q = blk_get_queue(dev)) == NULL)
diff -Nru a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
--- a/drivers/block/ll_rw_blk.c	Tue Apr 30 17:10:23 2002
+++ b/drivers/block/ll_rw_blk.c	Tue Apr 30 17:10:23 2002
@@ -109,46 +109,21 @@
 }
 
 /**
- * blk_set_readahead - set a queue's readahead tunable
+ * blk_get_ra_pages - get the address of a queue's readahead tunable
  * @dev:	device
- * @sectors:	readahead, in 512 byte sectors
  *
- * Returns zero on success, else negative errno
- */
-int blk_set_readahead(struct block_device *bdev, unsigned sectors)
-{
-	int ret = -EINVAL;
-	request_queue_t *q = blk_get_queue(to_kdev_t(bdev->bd_dev));
-
-	if (q) {
-		q->ra_sectors = sectors;
-		blk_put_queue(q);
-		ret = 0;
-	}
-	return ret;
-}
-
-/**
- * blk_get_readahead - query a queue's readahead tunable
- * @dev:	device
- *
- * Locates the passed device's request queue and returns its
+ * Locates the passed device's request queue and returns the address of its
  * readahead setting.
  *
- * The returned value is in units of 512 byte sectors.
- *
- * Will return zero if the queue has never had its readahead
- * setting altered.
+ * Will return NULL if the request queue cannot be located.
  */
-unsigned blk_get_readahead(struct block_device *bdev)
+unsigned long *blk_get_ra_pages(kdev_t dev)
 {
-	unsigned ret = 0;
-	request_queue_t *q = blk_get_queue(to_kdev_t(bdev->bd_dev));
+	unsigned long *ret = NULL;
+	request_queue_t *q = blk_get_queue(dev);
 
-	if (q) {
-		ret = q->ra_sectors;
-		blk_put_queue(q);
-	}
+	if (q)
+		ret = &q->ra_pages;
 	return ret;
 }
 
@@ -187,7 +162,7 @@
 	q->max_phys_segments = MAX_PHYS_SEGMENTS;
 	q->max_hw_segments = MAX_HW_SEGMENTS;
 	q->make_request_fn = mfn;
-	q->ra_sectors = VM_MAX_READAHEAD << (10 - 9);	/* kbytes->sectors */
+	q->ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
 	blk_queue_max_sectors(q, MAX_SECTORS);
 	blk_queue_hardsect_size(q, 512);
 
@@ -1430,11 +1405,16 @@
 {
 	struct bio *bio;
 
-	BUG_ON(!test_bit(BH_Lock, &bh->b_state));
+	BUG_ON(!buffer_locked(bh));
 	BUG_ON(!buffer_mapped(bh));
 	BUG_ON(!bh->b_end_io);
 
-	set_bit(BH_Req, &bh->b_state);
+	if ((rw == READ || rw == READA) && buffer_uptodate(bh))
+		printk("%s: read of uptodate buffer\n", __FUNCTION__);
+	if (rw == WRITE && !buffer_uptodate(bh))
+		printk("%s: write of non-uptodate buffer\n", __FUNCTION__);
+		
+	set_buffer_req(bh);
 
 	/*
 	 * from here on down, it's all bio -- do the initial mapping,
@@ -1490,6 +1470,7 @@
  *  a multiple of the current approved size for the device.
  *
  **/
+
 void ll_rw_block(int rw, int nr, struct buffer_head * bhs[])
 {
 	unsigned int major;
@@ -1526,7 +1507,7 @@
 		struct buffer_head *bh = bhs[i];
 
 		/* Only one thread can actually submit the I/O. */
-		if (test_and_set_bit(BH_Lock, &bh->b_state))
+		if (test_set_buffer_locked(bh))
 			continue;
 
 		/* We have the buffer lock */
@@ -1535,10 +1516,9 @@
 
 		switch(rw) {
 		case WRITE:
-			if (!atomic_set_buffer_clean(bh))
+			if (!test_clear_buffer_dirty(bh))
 				/* Hmmph! Nothing to write */
 				goto end_io;
-			__mark_buffer_clean(bh);
 			break;
 
 		case READA:
@@ -1550,7 +1530,7 @@
 		default:
 			BUG();
 	end_io:
-			bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state));
+			bh->b_end_io(bh, buffer_uptodate(bh));
 			continue;
 		}
 
@@ -1561,7 +1541,7 @@
 sorry:
 	/* Make sure we don't get infinite dirty retries.. */
 	for (i = 0; i < nr; i++)
-		mark_buffer_clean(bhs[i]);
+		clear_buffer_dirty(bhs[i]);
 }
 
 #ifdef CONFIG_STRAM_SWAP
diff -Nru a/drivers/block/loop.c b/drivers/block/loop.c
--- a/drivers/block/loop.c	Tue Apr 30 17:10:23 2002
+++ b/drivers/block/loop.c	Tue Apr 30 17:10:23 2002
@@ -217,14 +217,14 @@
 		offset = 0;
 		index++;
 		pos += size;
-		UnlockPage(page);
+		unlock_page(page);
 		page_cache_release(page);
 	}
 	up(&mapping->host->i_sem);
 	return 0;
 
 unlock:
-	UnlockPage(page);
+	unlock_page(page);
 	page_cache_release(page);
 fail:
 	up(&mapping->host->i_sem);
@@ -547,8 +547,6 @@
 	lo->lo_state = Lo_bound;
 	atomic_inc(&lo->lo_pending);
 	spin_unlock_irq(&lo->lo_lock);
-
-	current->flags |= PF_NOIO;
 
 	/*
 	 * up sem, we are running
diff -Nru a/drivers/block/paride/Makefile b/drivers/block/paride/Makefile
--- a/drivers/block/paride/Makefile	Tue Apr 30 17:10:25 2002
+++ b/drivers/block/paride/Makefile	Tue Apr 30 17:10:25 2002
@@ -7,7 +7,7 @@
 
 L_TARGET := paride.a
 
-export-objs := bpck6.o
+export-objs := paride.o bpck6.o
 
 obj-$(CONFIG_PARIDE)		+= paride.o
 obj-$(CONFIG_PARIDE_PD)		+= pd.o
diff -Nru a/drivers/block/paride/paride.c b/drivers/block/paride/paride.c
--- a/drivers/block/paride/paride.c	Tue Apr 30 17:10:23 2002
+++ b/drivers/block/paride/paride.c	Tue Apr 30 17:10:23 2002
@@ -51,21 +51,29 @@
 {	pi->proto->write_regr(pi,cont,regr,val);
 }
 
+EXPORT_SYMBOL(pi_write_regr);
+
 int pi_read_regr( PIA *pi, int cont, int regr)
 
 {	return pi->proto->read_regr(pi,cont,regr);
 }
 
+EXPORT_SYMBOL(pi_read_regr);
+
 void pi_write_block( PIA *pi, char * buf, int count)
 
 {	pi->proto->write_block(pi,buf,count);
 }
 
+EXPORT_SYMBOL(pi_write_block);
+
 void pi_read_block( PIA *pi, char * buf, int count)
 
 {       pi->proto->read_block(pi,buf,count);
 }
 
+EXPORT_SYMBOL(pi_read_block);
+
 #ifdef CONFIG_PARPORT
 
 static void pi_wake_up( void *p)
@@ -116,6 +124,8 @@
 
 #endif
 
+EXPORT_SYMBOL(pi_do_claimed);
+
 static void pi_claim( PIA *pi)
 
 {	if (pi->claimed) return;
@@ -141,12 +151,16 @@
 	pi->proto->connect(pi);
 }
 
+EXPORT_SYMBOL(pi_connect);
+
 void pi_disconnect( PIA *pi)
 
 {	pi->proto->disconnect(pi);
 	pi_unclaim(pi);
 }
 
+EXPORT_SYMBOL(pi_disconnect);
+
 static void pi_unregister_parport( PIA *pi)
 
 {
@@ -168,6 +182,8 @@
 	pi->proto->release_proto(pi);
 }
 
+EXPORT_SYMBOL(pi_release);
+
 #define WR(r,v)         pi_write_regr(pi,0,r,v)
 #define RR(r)           (pi_read_regr(pi,0,r))
 
@@ -226,6 +242,8 @@
 	return 1;
 }	
 
+EXPORT_SYMBOL(pi_register);
+
 void pi_unregister( PIP *pr)
 
 {	if (!pr) return;
@@ -237,6 +255,8 @@
 	MOD_DEC_USE_COUNT;
 }
 
+EXPORT_SYMBOL(pi_unregister);
+
 static int pi_register_parport( PIA *pi, int verbose)
 
 {
@@ -415,6 +435,8 @@
 
 	return 1;
 }
+
+EXPORT_SYMBOL(pi_init);
 
 #ifdef MODULE
 
diff -Nru a/drivers/block/rd.c b/drivers/block/rd.c
--- a/drivers/block/rd.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/block/rd.c	Tue Apr 30 17:10:25 2002
@@ -106,19 +106,19 @@
  */
 static int ramdisk_readpage(struct file *file, struct page * page)
 {
-	if (!Page_Uptodate(page)) {
+	if (!PageUptodate(page)) {
 		memset(kmap(page), 0, PAGE_CACHE_SIZE);
 		kunmap(page);
 		flush_dcache_page(page);
 		SetPageUptodate(page);
 	}
-	UnlockPage(page);
+	unlock_page(page);
 	return 0;
 }
 
 static int ramdisk_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to)
 {
-	if (!Page_Uptodate(page)) {
+	if (!PageUptodate(page)) {
 		void *addr = page_address(page);
 		memset(addr, 0, PAGE_CACHE_SIZE);
 		flush_dcache_page(page);
@@ -173,7 +173,7 @@
 				goto out;
 			err = 0;
 
-			if (!Page_Uptodate(page)) {
+			if (!PageUptodate(page)) {
 				memset(kmap(page), 0, PAGE_CACHE_SIZE);
 				kunmap(page);
 				SetPageUptodate(page);
@@ -206,7 +206,7 @@
 			SetPageDirty(page);
 		}
 		if (unlock)
-			UnlockPage(page);
+			unlock_page(page);
 		__free_page(page);
 	} while (size);
 
diff -Nru a/drivers/char/Makefile b/drivers/char/Makefile
--- a/drivers/char/Makefile	Tue Apr 30 17:10:25 2002
+++ b/drivers/char/Makefile	Tue Apr 30 17:10:25 2002
@@ -16,7 +16,8 @@
 
 export-objs     :=	busmouse.o console.o keyboard.o sysrq.o \
 			misc.o pty.o random.o selection.o serial.o \
-			sonypi.o tty_io.o tty_ioctl.o generic_serial.o rtc.o
+			sonypi.o tty_io.o tty_ioctl.o generic_serial.o rtc.o \
+			ip2main.o
 
 mod-subdirs	:=	ftape drm pcmcia
 
diff -Nru a/drivers/char/agp/agpgart_be.c b/drivers/char/agp/agpgart_be.c
--- a/drivers/char/agp/agpgart_be.c	Tue Apr 30 17:10:24 2002
+++ b/drivers/char/agp/agpgart_be.c	Tue Apr 30 17:10:24 2002
@@ -770,7 +770,7 @@
 		return 0;
 
 	get_page(page);
-	LockPage(page);
+	SetPageLocked(page);
 	atomic_inc(&agp_bridge.current_memory_agp);
 	return (unsigned long)page_address(page);
 }
@@ -785,7 +785,7 @@
 
 	page = virt_to_page(pt);
 	put_page(page);
-	UnlockPage(page);
+	unlock_page(page);
 	free_page((unsigned long) pt);
 	atomic_dec(&agp_bridge.current_memory_agp);
 }
@@ -2744,7 +2744,7 @@
 		return 0;
 
 	get_page(page);
-	LockPage(page);
+	SetPageLocked(page);
 	atomic_inc(&agp_bridge.current_memory_agp);
 
 	global_cache_flush();
@@ -2780,7 +2780,7 @@
 
 	page = virt_to_page(pt);
 	put_page(page);
-	UnlockPage(page);
+	unlock_page(page);
 	free_page((unsigned long) pt);
 	atomic_dec(&agp_bridge.current_memory_agp);
 }
diff -Nru a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c
--- a/drivers/char/drm/i810_dma.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/char/drm/i810_dma.c	Tue Apr 30 17:10:25 2002
@@ -287,7 +287,7 @@
 		return 0;
 
 	get_page(virt_to_page(address));
-	LockPage(virt_to_page(address));
+	SetPageLocked(virt_to_page(address));
 
 	return address;
 }
@@ -297,7 +297,7 @@
 	if (page) {
 		struct page *p = virt_to_page(page);
 		put_page(p);
-		UnlockPage(p);
+		unlock_page(p);
 		free_page(page);
 	}
 }
diff -Nru a/drivers/char/ip2main.c b/drivers/char/ip2main.c
--- a/drivers/char/ip2main.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/char/ip2main.c	Tue Apr 30 17:10:25 2002
@@ -579,7 +579,7 @@
 /* SA_RANDOM   - can be source for cert. random number generators */
 #define IP2_SA_FLAGS	0
 
-int __init
+int
 ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) 
 {
 #ifdef	CONFIG_DEVFS_FS
@@ -973,6 +973,8 @@
 
 	return 0;
 }
+
+EXPORT_SYMBOL(ip2_loadmain);
 
 /******************************************************************************/
 /* Function:   ip2_init_board()                                               */
diff -Nru a/drivers/ide/Config.help b/drivers/ide/Config.help
--- a/drivers/ide/Config.help	Tue Apr 30 17:10:25 2002
+++ b/drivers/ide/Config.help	Tue Apr 30 17:10:25 2002
@@ -299,13 +299,6 @@
 
   It is normally safe to answer Y; however, the default is N.
 
-CONFIG_IDEDMA_PCI_WIP
-  If you enable this you will be able to use and test highly
-  developmental projects. If you say N, the configurator will
-  simply skip those options.
-
-  It is SAFEST to say N to this question.
-
 CONFIG_BLK_DEV_PDC_ADMA
   Please read the comments at the top of <file:drivers/ide/ide-pci.c>.
 
@@ -430,6 +423,15 @@
   and also for the Efar Victory66 (slc90e66) chip.  This allows
   the kernel to change PIO, DMA and UDMA speeds and to configure
   the chip to optimum performance.
+
+CONFIG_BLK_DEV_PIIX_TRY133
+  The ICH2, ICH2-M, ICH3, ICH3-M, ICH3-S and CICH chips can support
+  UDMA133 in hardware, even though the specifications of the chips
+  say otherwise. By enabling this option, you allow the driver to
+  enable the UDMA133 mode on these chips.
+
+  If you want to stay on the safe side, say N here.
+  If you prefer maximum performance, say Y here.
 
 CONFIG_BLK_DEV_PDC202XX
   Promise Ultra33 or PDC20246
diff -Nru a/drivers/ide/Config.in b/drivers/ide/Config.in
--- a/drivers/ide/Config.in	Tue Apr 30 17:10:25 2002
+++ b/drivers/ide/Config.in	Tue Apr 30 17:10:25 2002
@@ -47,27 +47,29 @@
 	 dep_bool '      Use PCI DMA by default when available' CONFIG_IDEDMA_PCI_AUTO $CONFIG_BLK_DEV_IDEDMA_PCI
          dep_bool '    Enable DMA only for disks ' CONFIG_IDEDMA_ONLYDISK $CONFIG_IDEDMA_PCI_AUTO
 	 define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_PCI
-	 dep_bool '    ATA Work(s) In Progress (EXPERIMENTAL)' CONFIG_IDEDMA_PCI_WIP $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL
-	 dep_bool '    Good-Bad DMA Model-Firmware (WIP)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS $CONFIG_IDEDMA_PCI_WIP
+	 dep_bool '    Good-Bad DMA Model-Firmware (EXPERIMENTAL)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS $CONFIG_EXPERIMENTAL
 	 dep_bool '    AEC62XX chipset support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI
 	 dep_mbool '      AEC62XX Tuning support' CONFIG_AEC62XX_TUNING $CONFIG_BLK_DEV_AEC62XX
 	 dep_bool '    ALI M15x3 chipset support' CONFIG_BLK_DEV_ALI15X3 $CONFIG_BLK_DEV_IDEDMA_PCI
-	 dep_mbool '      ALI M15x3 WDC support (DANGEROUS)' CONFIG_WDC_ALI15X3 $CONFIG_BLK_DEV_ALI15X3
+	 dep_mbool '      ALI M15x3 WDC support (DANGEROUS)' CONFIG_WDC_ALI15X3 $CONFIG_BLK_DEV_ALI15X3 $CONFIG_EXPERIMENTAL
 	 dep_bool '    AMD and nVidia chipset support' CONFIG_BLK_DEV_AMD74XX $CONFIG_BLK_DEV_IDEDMA_PCI
 	 dep_bool '    CMD64X chipset support' CONFIG_BLK_DEV_CMD64X $CONFIG_BLK_DEV_IDEDMA_PCI
 	 dep_bool '    CY82C693 chipset support' CONFIG_BLK_DEV_CY82C693 $CONFIG_BLK_DEV_IDEDMA_PCI
 	 dep_bool '    Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 $CONFIG_BLK_DEV_IDEDMA_PCI
   	 dep_bool '    HPT34X chipset support' CONFIG_BLK_DEV_HPT34X $CONFIG_BLK_DEV_IDEDMA_PCI
-	 dep_mbool '      HPT34X AUTODMA support (WIP)' CONFIG_HPT34X_AUTODMA $CONFIG_BLK_DEV_HPT34X $CONFIG_IDEDMA_PCI_WIP
+	 dep_mbool '      HPT34X AUTODMA support (EXPERMENTAL)' CONFIG_HPT34X_AUTODMA $CONFIG_BLK_DEV_HPT34X $CONFIG_EXPERIMENTAL
 	 dep_bool '    HPT366 chipset support' CONFIG_BLK_DEV_HPT366 $CONFIG_BLK_DEV_IDEDMA_PCI
 	 dep_bool '    Intel and Efar (SMsC) chipset support' CONFIG_BLK_DEV_PIIX $CONFIG_BLK_DEV_IDEDMA_PCI
+	 if [ "$CONFIG_BLK_DEV_PIIX" = "y" ]; then
+	    dep_bool '      Use UDMA133 even on ICH2, ICH3 and CICH chips (EXPERIMENTAL)' CONFIG_BLK_DEV_PIIX_TRY133 $CONFIG_EXPERIMENTAL
+	 fi
 	 if [ "$CONFIG_MIPS_ITE8172" = "y" -o "$CONFIG_MIPS_IVR" = "y" ]; then
 	    dep_mbool '    IT8172 IDE support' CONFIG_BLK_DEV_IT8172 $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_mbool '      IT8172 IDE Tuning support' CONFIG_IT8172_TUNING $CONFIG_BLK_DEV_IT8172 $CONFIG_IDEDMA_PCI_AUTO
 	 fi
 	 dep_bool '    NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI
 	 dep_bool '    OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 $CONFIG_EXPERIMENTAL
-	 dep_mbool '    Pacific Digital A-DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC_ADMA $CONFIG_IDEDMA_PCI_WIP
+	 dep_mbool '    Pacific Digital A-DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC_ADMA $CONFIG_EXPERIMENTAL
 	 dep_bool '    PROMISE PDC202{46|62|65|67|68|69|70} support' CONFIG_BLK_DEV_PDC202XX $CONFIG_BLK_DEV_IDEDMA_PCI
 	 dep_bool '      Special UDMA Feature' CONFIG_PDC202XX_BURST $CONFIG_BLK_DEV_PDC202XX
 	 dep_bool '      Special FastTrak Feature' CONFIG_PDC202XX_FORCE $CONFIG_BLK_DEV_PDC202XX
diff -Nru a/drivers/ide/aec62xx.c b/drivers/ide/aec62xx.c
--- a/drivers/ide/aec62xx.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/ide/aec62xx.c	Tue Apr 30 17:10:25 2002
@@ -437,7 +437,7 @@
 
 	if (id && (id->capability & 1) && drive->channel->autodma) {
 		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+		if (ide_dmaproc(ide_dma_bad_drive, drive, NULL)) {
 			dma_func = ide_dma_off;
 			goto fast_ata_pio;
 		}
@@ -459,7 +459,7 @@
 				if (dma_func != ide_dma_on)
 					goto no_dma_set;
 			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
+		} else if (ide_dmaproc(ide_dma_good_drive, drive, NULL)) {
 			if (id->eide_dma_time > 150) {
 				goto no_dma_set;
 			}
@@ -476,13 +476,13 @@
 no_dma_set:
 		aec62xx_tune_drive(drive, 5);
 	}
-	return drive->channel->dmaproc(dma_func, drive);
+	return drive->channel->udma(dma_func, drive, NULL);
 }
 
 /*
  * aec62xx_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
  */
-int aec62xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+int aec62xx_dmaproc (ide_dma_action_t func, struct ata_device *drive, struct request *rq)
 {
 	switch (func) {
 		case ide_dma_check:
@@ -507,7 +507,7 @@
 		default:
 			break;
 	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
+	return ide_dmaproc(func, drive, rq);	/* use standard DMA stuff */
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 #endif /* CONFIG_AEC62XX_TUNING */
@@ -542,17 +542,17 @@
 void __init ide_init_aec62xx(struct ata_channel *hwif)
 {
 #ifdef CONFIG_AEC62XX_TUNING
-	hwif->tuneproc = &aec62xx_tune_drive;
-	hwif->speedproc = &aec62xx_tune_chipset;
-#ifdef CONFIG_BLK_DEV_IDEDMA
+	hwif->tuneproc = aec62xx_tune_drive;
+	hwif->speedproc = aec62xx_tune_chipset;
+# ifdef CONFIG_BLK_DEV_IDEDMA
 	if (hwif->dma_base)
-		hwif->dmaproc = &aec62xx_dmaproc;
+		hwif->udma = aec62xx_dmaproc;
 	hwif->highmem = 1;
-#else /* !CONFIG_BLK_DEV_IDEDMA */
+# else
 	hwif->drives[0].autotune = 1;
 	hwif->drives[1].autotune = 1;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-#endif /* CONFIG_AEC62XX_TUNING */
+# endif
+#endif
 }
 
 void __init ide_dmacapable_aec62xx(struct ata_channel *hwif, unsigned long dmabase)
diff -Nru a/drivers/ide/alim15x3.c b/drivers/ide/alim15x3.c
--- a/drivers/ide/alim15x3.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/ide/alim15x3.c	Tue Apr 30 17:10:25 2002
@@ -437,11 +437,11 @@
 	byte can_ultra_dma = ali15x3_can_ultra(drive);
 
 	if ((m5229_revision<=0x20) && (drive->type != ATA_DISK))
-		return hwif->dmaproc(ide_dma_off_quietly, drive);
+		return hwif->udma(ide_dma_off_quietly, drive, NULL);
 
 	if ((id != NULL) && ((id->capability & 1) != 0) && hwif->autodma) {
 		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+		if (ide_dmaproc(ide_dma_bad_drive, drive, NULL)) {
 			dma_func = ide_dma_off;
 			goto fast_ata_pio;
 		}
@@ -463,7 +463,7 @@
 				if (dma_func != ide_dma_on)
 					goto no_dma_set;
 			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
+		} else if (ide_dmaproc(ide_dma_good_drive, drive, NULL)) {
 			if (id->eide_dma_time > 150) {
 				goto no_dma_set;
 			}
@@ -480,10 +480,10 @@
 no_dma_set:
 		config_chipset_for_pio(drive);
 	}
-	return hwif->dmaproc(dma_func, drive);
+	return hwif->udma(dma_func, drive, NULL);
 }
 
-static int ali15x3_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+static int ali15x3_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq)
 {
 	switch(func) {
 		case ide_dma_check:
@@ -495,7 +495,7 @@
 		default:
 			break;
 	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
+	return ide_dmaproc(func, drive, rq);	/* use standard DMA stuff */
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
@@ -672,14 +672,14 @@
 	hwif->tuneproc = &ali15x3_tune_drive;
 	hwif->drives[0].autotune = 1;
 	hwif->drives[1].autotune = 1;
-	hwif->speedproc = &ali15x3_tune_chipset;
+	hwif->speedproc = ali15x3_tune_chipset;
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if ((hwif->dma_base) && (m5229_revision >= 0x20)) {
 		/*
 		 * M1543C or newer for DMAing
 		 */
-		hwif->dmaproc = &ali15x3_dmaproc;
+		hwif->udma = ali15x3_dmaproc;
 		hwif->autodma = 1;
 	}
 
diff -Nru a/drivers/ide/amd74xx.c b/drivers/ide/amd74xx.c
--- a/drivers/ide/amd74xx.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/ide/amd74xx.c	Tue Apr 30 17:10:25 2002
@@ -282,7 +282,7 @@
  * else to the default ide_dmaproc().
  */
 
-int amd74xx_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
+int amd74xx_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq)
 {
 
 	if (func == ide_dma_check) {
@@ -301,7 +301,7 @@
 			? ide_dma_on : ide_dma_off_quietly;
 	}
 
-	return ide_dmaproc(func, drive);
+	return ide_dmaproc(func, drive, rq);
 }
 
 #endif /* CONFIG_BLK_DEV_IDEDMA */
@@ -433,13 +433,13 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (hwif->dma_base) {
 		hwif->highmem = 1;
-		hwif->dmaproc = &amd74xx_dmaproc;
-#ifdef CONFIG_IDEDMA_AUTO
+		hwif->udma = amd74xx_dmaproc;
+# ifdef CONFIG_IDEDMA_AUTO
 		if (!noautodma)
 			hwif->autodma = 1;
-#endif
+# endif
 	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
+#endif
 }
 
 /*
diff -Nru a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c
--- a/drivers/ide/cmd64x.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/ide/cmd64x.c	Tue Apr 30 17:10:25 2002
@@ -759,7 +759,7 @@
 	ide_dma_action_t dma_func = ide_dma_on;
 
 	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;	
+	class_rev &= 0xff;
 
 	switch(dev->device) {
 		case PCI_DEVICE_ID_CMD_680:
@@ -777,13 +777,13 @@
 			can_ultra_100 = 0;
 			break;
 		default:
-			return hwif->dmaproc(ide_dma_off, drive);
+			return hwif->udma(ide_dma_off, drive, NULL);
 	}
 
 	if ((id != NULL) && ((id->capability & 1) != 0) &&
 	    hwif->autodma && (drive->type == ATA_DISK)) {
 		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+		if (ide_dmaproc(ide_dma_bad_drive, drive, NULL)) {
 			dma_func = ide_dma_off;
 			goto fast_ata_pio;
 		}
@@ -805,7 +805,7 @@
 				if (dma_func != ide_dma_on)
 					goto no_dma_set;
 			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
+		} else if (ide_dmaproc(ide_dma_good_drive, drive, NULL)) {
 			if (id->eide_dma_time > 150) {
 				goto no_dma_set;
 			}
@@ -822,10 +822,10 @@
 no_dma_set:
 		config_chipset_for_pio(drive, 1);
 	}
-	return drive->channel->dmaproc(dma_func, drive);
+	return drive->channel->udma(dma_func, drive, NULL);
 }
 
-static int cmd680_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+static int cmd680_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq)
 {
 	switch (func) {
 		case ide_dma_check:
@@ -834,10 +834,10 @@
 			break;
 	}
 	/* Other cases are done by generic IDE-DMA code. */
-        return ide_dmaproc(func, drive);
+        return ide_dmaproc(func, drive, rq);
 }
 
-static int cmd64x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+static int cmd64x_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq)
 {
 	byte dma_stat		= 0;
 	byte dma_alt_stat	= 0;
@@ -882,14 +882,14 @@
 			break;
 	}
 	/* Other cases are done by generic IDE-DMA code. */
-	return ide_dmaproc(func, drive);
+	return ide_dmaproc(func, drive, rq);
 }
 
 /*
  * ASUS P55T2P4D with CMD646 chipset revision 0x01 requires the old
  * event order for DMA transfers.
  */
-static int cmd646_1_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+static int cmd646_1_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq)
 {
 	struct ata_channel *hwif = drive->channel;
 	unsigned long dma_base = hwif->dma_base;
@@ -910,7 +910,7 @@
 	}
 
 	/* Other cases are done by generic IDE-DMA code. */
-	return ide_dmaproc(func, drive);
+	return ide_dmaproc(func, drive, rq);
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
@@ -1125,7 +1125,7 @@
 	switch(dev->device) {
 		case PCI_DEVICE_ID_CMD_680:
 			hwif->busproc	= &cmd680_busproc;
-			hwif->dmaproc	= &cmd680_dmaproc;
+			hwif->udma	= &cmd680_dmaproc;
 			hwif->resetproc = &cmd680_reset;
 			hwif->speedproc	= &cmd680_tune_chipset;
 			hwif->tuneproc	= &cmd680_tuneproc;
@@ -1133,16 +1133,16 @@
 		case PCI_DEVICE_ID_CMD_649:
 		case PCI_DEVICE_ID_CMD_648:
 		case PCI_DEVICE_ID_CMD_643:
-			hwif->dmaproc	= &cmd64x_dmaproc;
+			hwif->udma	= &cmd64x_dmaproc;
 			hwif->tuneproc	= &cmd64x_tuneproc;
 			hwif->speedproc = &cmd64x_tune_chipset;
 			break;
 		case PCI_DEVICE_ID_CMD_646:
 			hwif->chipset = ide_cmd646;
 			if (class_rev == 0x01) {
-				hwif->dmaproc = &cmd646_1_dmaproc;
+				hwif->udma = &cmd646_1_dmaproc;
 			} else {
-				hwif->dmaproc = &cmd64x_dmaproc;
+				hwif->udma = &cmd64x_dmaproc;
 			}
 			hwif->tuneproc	= &cmd64x_tuneproc;
 			hwif->speedproc	= &cmd64x_tune_chipset;
diff -Nru a/drivers/ide/cs5530.c b/drivers/ide/cs5530.c
--- a/drivers/ide/cs5530.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/ide/cs5530.c	Tue Apr 30 17:10:25 2002
@@ -144,7 +144,7 @@
 	/*
 	 * Default to DMA-off in case we run into trouble here.
 	 */
-	(void)hwif->dmaproc(ide_dma_off_quietly, drive);	/* turn off DMA while we fiddle */
+	hwif->udma(ide_dma_off_quietly, drive, NULL);
 	outb(inb(hwif->dma_base+2)&~(unit?0x40:0x20), hwif->dma_base+2); /* clear DMA_capable bit */
 
 	/*
@@ -158,7 +158,7 @@
 	 */
 	if (mate->present) {
 		struct hd_driveid *mateid = mate->id;
-		if (mateid && (mateid->capability & 1) && !hwif->dmaproc(ide_dma_bad_drive, mate)) {
+		if (mateid && (mateid->capability & 1) && !hwif->udma(ide_dma_bad_drive, mate, NULL)) {
 			if ((mateid->field_valid & 4) && (mateid->dma_ultra & 7))
 				udma_ok = 1;
 			else if ((mateid->field_valid & 2) && (mateid->dma_mword & 7))
@@ -172,7 +172,7 @@
 	 * Now see what the current drive is capable of,
 	 * selecting UDMA only if the mate said it was ok.
 	 */
-	if (id && (id->capability & 1) && hwif->autodma && !hwif->dmaproc(ide_dma_bad_drive, drive)) {
+	if (id && (id->capability & 1) && hwif->autodma && !hwif->udma(ide_dma_bad_drive, drive, NULL)) {
 		if (udma_ok && (id->field_valid & 4) && (id->dma_ultra & 7)) {
 			if      (id->dma_ultra & 4)
 				mode = XFER_UDMA_2;
@@ -229,7 +229,7 @@
 	/*
 	 * Finally, turn DMA on in software, and exit.
 	 */
-	return hwif->dmaproc(ide_dma_on, drive);	/* success */
+	return hwif->udma(ide_dma_on, drive, NULL);	/* success */
 }
 
 /*
@@ -237,7 +237,7 @@
  * We need it for our custom "ide_dma_check" function.
  * All other requests are forwarded to the standard ide_dmaproc().
  */
-int cs5530_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+int cs5530_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq)
 {
 	switch (func) {
 		case ide_dma_check:
@@ -246,7 +246,7 @@
 			break;
 	}
 	/* Other cases are done by generic IDE-DMA code. */
-	return ide_dmaproc(func, drive);
+	return ide_dmaproc(func, drive, rq);
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
@@ -353,7 +353,7 @@
 		unsigned int basereg, d0_timings;
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	hwif->dmaproc  = &cs5530_dmaproc;
+	hwif->udma = cs5530_dmaproc;
 	hwif->highmem = 1;
 #else
 	hwif->autodma = 0;
diff -Nru a/drivers/ide/cy82c693.c b/drivers/ide/cy82c693.c
--- a/drivers/ide/cy82c693.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/ide/cy82c693.c	Tue Apr 30 17:10:25 2002
@@ -234,7 +234,7 @@
 /* 
  * used to set DMA mode for CY82C693 (single and multi modes)
  */
-static int cy82c693_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
+static int cy82c693_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq)
 {
 	/*
 	 * if the function is dma on, set dma mode for drive everything
@@ -247,14 +247,14 @@
 		printk (KERN_INFO "dma_on: %s\n", drive->name);
 #endif /* CY82C693_DEBUG_INFO */
 
-		if (id != NULL) {		
+		if (id != NULL) {
                        /* Enable DMA on any drive that has DMA (multi or single) enabled */
                        if (id->field_valid & 2) {       /* regular DMA */
 			       int mmode, smode;
 
 			       mmode = id->dma_mword & (id->dma_mword >> 8);
 			       smode = id->dma_1word & (id->dma_1word >> 8);
-			       		      
+
 		               if (mmode != 0)
 				     cy82c693_dma_enable(drive, (mmode >> 1), 0); /* enable multi */
 			       else if (smode != 0)
@@ -262,7 +262,7 @@
 			}
 		}
 	}
-        return ide_dmaproc(func, drive);
+        return ide_dmaproc(func, drive, rq);
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
@@ -442,7 +442,7 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (hwif->dma_base) {
 		hwif->highmem = 1;
-		hwif->dmaproc = cy82c693_dmaproc;
+		hwif->udma = cy82c693_dmaproc;
 		if (!noautodma)
 			hwif->autodma = 1;
 	}
diff -Nru a/drivers/ide/hpt34x.c b/drivers/ide/hpt34x.c
--- a/drivers/ide/hpt34x.c	Tue Apr 30 17:10:23 2002
+++ b/drivers/ide/hpt34x.c	Tue Apr 30 17:10:23 2002
@@ -334,7 +334,6 @@
 			drive->waiting_for_dma = 1;
 			if (drive->type != ATA_DISK)
 				return 0;
-			BUG_ON(HWGROUP(drive)->handler);
 			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);	/* issue cmd to drive */
 			OUT_BYTE((reading == 9) ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
 			return 0;
diff -Nru a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c
--- a/drivers/ide/hpt366.c	Tue Apr 30 17:10:23 2002
+++ b/drivers/ide/hpt366.c	Tue Apr 30 17:10:23 2002
@@ -750,7 +750,7 @@
 
 	if (id && (id->capability & 1) && drive->channel->autodma) {
 		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+		if (ide_dmaproc(ide_dma_bad_drive, drive, NULL)) {
 			dma_func = ide_dma_off;
 			goto fast_ata_pio;
 		}
@@ -771,7 +771,7 @@
 				if (dma_func != ide_dma_on)
 					goto no_dma_set;
 			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
+		} else if (ide_dmaproc(ide_dma_good_drive, drive, NULL)) {
 			if (id->eide_dma_time > 150) {
 				goto no_dma_set;
 			}
@@ -789,7 +789,7 @@
 
 		config_chipset_for_pio(drive);
 	}
-	return drive->channel->dmaproc(dma_func, drive);
+	return drive->channel->udma(dma_func, drive, NULL);
 }
 
 /*
@@ -798,7 +798,7 @@
  * This is specific to the HPT366 UDMA bios chipset
  * by HighPoint|Triones Technologies, Inc.
  */
-int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+int hpt366_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq)
 {
 	byte reg50h = 0, reg52h = 0, reg5ah = 0, dma_stat = 0;
 	unsigned long dma_base = drive->channel->dma_base;
@@ -829,10 +829,10 @@
 		default:
 			break;
 	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
+	return ide_dmaproc(func, drive, rq);	/* use standard DMA stuff */
 }
 
-int hpt370_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+int hpt370_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq)
 {
 	struct ata_channel *hwif = drive->channel;
 	unsigned long dma_base = hwif->dma_base;
@@ -883,7 +883,7 @@
 		default:
 			break;
 	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
+	return ide_dmaproc(func, drive, rq);	/* use standard DMA stuff */
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
@@ -1185,9 +1185,9 @@
 			pci_read_config_byte(hwif->pci_dev, 0x5a, &reg5ah);
 			if (reg5ah & 0x10)	/* interrupt force enable */
 				pci_write_config_byte(hwif->pci_dev, 0x5a, reg5ah & ~0x10);
-			hwif->dmaproc = &hpt370_dmaproc;
+			hwif->udma = hpt370_dmaproc;
 		} else {
-			hwif->dmaproc = &hpt366_dmaproc;
+			hwif->udma = hpt366_dmaproc;
 		}
 		if (!noautodma)
 			hwif->autodma = 1;
diff -Nru a/drivers/ide/icside.c b/drivers/ide/icside.c
--- a/drivers/ide/icside.c	Tue Apr 30 17:10:23 2002
+++ b/drivers/ide/icside.c	Tue Apr 30 17:10:23 2002
@@ -327,7 +327,7 @@
 /*
  * dma_intr() is the handler for disk read/write DMA interrupts
  */
-static ide_startstop_t icside_dmaintr(ide_drive_t *drive)
+static ide_startstop_t icside_dmaintr(struct ata_device *drive, struct request *rq)
 {
 	int i;
 	byte stat, dma_stat;
@@ -336,15 +336,13 @@
 	stat = GET_STAT();			/* get drive status */
 	if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
 		if (!dma_stat) {
-			struct request *rq = HWGROUP(drive)->rq;
-			rq = HWGROUP(drive)->rq;
 			for (i = rq->nr_sectors; i > 0;) {
 				i -= rq->current_nr_sectors;
 				ide_end_request(drive, 1);
 			}
 			return ide_stopped;
 		}
-		printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n", 
+		printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n",
 		       drive->name, dma_stat);
 	}
 	return ide_error(drive, "dma_intr", stat);
@@ -443,8 +441,7 @@
 		if (drive->type != ATA_DISK)
 			return 0;
 
-		BUG_ON(HWGROUP(drive)->handler);
-		ide_set_handler(drive, &icside_dmaintr, WAIT_CMD, NULL);
+		ide_set_handler(drive, icside_dmaintr, WAIT_CMD, NULL);
 		OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA,
 			 IDE_COMMAND_REG);
 
diff -Nru a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
--- a/drivers/ide/ide-cd.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/ide/ide-cd.c	Tue Apr 30 17:10:25 2002
@@ -548,26 +548,23 @@
 }
 
 
-static void cdrom_end_request(ide_drive_t *drive, int uptodate)
+static void cdrom_end_request(struct ata_device *drive, struct request *rq, int uptodate)
 {
-	struct request *rq = HWGROUP(drive)->rq;
-
 	if ((rq->flags & REQ_SENSE) && uptodate)
 		cdrom_analyze_sense_data(drive, rq);
 
 	if ((rq->flags & REQ_CMD) && !rq->current_nr_sectors)
 		uptodate = 1;
 
-	ide_end_request(drive, uptodate);
+	ide_end_request(drive, rq, uptodate);
 }
 
 
 /* Returns 0 if the request should be continued.
    Returns 1 if the request was ended. */
-static int cdrom_decode_status (ide_startstop_t *startstop, ide_drive_t *drive,
+static int cdrom_decode_status(ide_startstop_t *startstop, struct ata_device *drive, struct request *rq,
 				int good_stat, int *stat_ret)
 {
-	struct request *rq = HWGROUP(drive)->rq;
 	int stat, err, sense_key;
 	struct packet_command *pc;
 
@@ -583,7 +580,7 @@
 	sense_key = err >> 4;
 
 	if (rq == NULL) {
-		printk("%s: missing rq in cdrom_decode_status\n", drive->name);
+		printk("%s: missing rq in %s\n", drive->name, __FUNCTION__);
 		*startstop = ide_stopped;
 		return 1;
 	}
@@ -596,7 +593,7 @@
 		/* FIXME --mdcki */
 		pc = (struct packet_command *) rq->special;
 		pc->stat = 1;
-		cdrom_end_request(drive, 1);
+		cdrom_end_request(drive, rq, 1);
 		*startstop = ide_error (drive, "request sense failure", stat);
 
 		return 1;
@@ -634,7 +631,7 @@
 		}
 
 		pc->stat = 1;
-		cdrom_end_request(drive, 1);
+		cdrom_end_request(drive, rq, 1);
 
 		/* FIXME: this is the only place where pc->sense get's used.
 		 * Think hard about how to get rid of it...
@@ -651,7 +648,7 @@
 
 			/* Fail the request. */
 			printk ("%s: tray open\n", drive->name);
-			cdrom_end_request(drive, 0);
+			cdrom_end_request(drive, rq, 0);
 		} else if (sense_key == UNIT_ATTENTION) {
 			/* Media change. */
 			cdrom_saw_media_change (drive);
@@ -660,27 +657,27 @@
 			   But be sure to give up if we've retried
 			   too many times. */
 			if (++rq->errors > ERROR_MAX)
-				cdrom_end_request(drive, 0);
+				cdrom_end_request(drive, rq, 0);
 		} else if (sense_key == ILLEGAL_REQUEST ||
 			   sense_key == DATA_PROTECT) {
 			/* No point in retrying after an illegal
 			   request or data protect error.*/
 			ide_dump_status (drive, "command error", stat);
-			cdrom_end_request(drive, 0);
+			cdrom_end_request(drive, rq,  0);
 		} else if (sense_key == MEDIUM_ERROR) {
 			/* No point in re-trying a zillion times on a bad
 			 * sector.  The error is not correctable at all.
 			 */
 			ide_dump_status (drive, "media error (bad sector)", stat);
-			cdrom_end_request(drive, 0);
+			cdrom_end_request(drive, rq, 0);
 		} else if ((err & ~ABRT_ERR) != 0) {
 			/* Go to the default handler
 			   for other errors. */
-			*startstop = ide_error (drive, "cdrom_decode_status", stat);
+			*startstop = ide_error (drive, __FUNCTION__, stat);
 			return 1;
 		} else if ((++rq->errors > ERROR_MAX)) {
 			/* We've racked up too many retries.  Abort. */
-			cdrom_end_request(drive, 0);
+			cdrom_end_request(drive, rq, 0);
 		}
 
 		/* If we got a CHECK_CONDITION status,
@@ -695,9 +692,8 @@
 	return 1;
 }
 
-static int cdrom_timer_expiry(ide_drive_t *drive)
+static int cdrom_timer_expiry(struct ata_device *drive, struct request *rq)
 {
-	struct request *rq = HWGROUP(drive)->rq;
 	unsigned long wait = 0;
 
 	/*
@@ -727,9 +723,10 @@
    called when the interrupt from the drive arrives.  Otherwise, HANDLER
    will be called immediately after the drive is prepared for the transfer. */
 
-static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive,
+static ide_startstop_t cdrom_start_packet_command(struct ata_device *drive,
+						  struct request *rq,
 						  int xferlen,
-						  ide_handler_t *handler)
+						  ata_handler_t handler)
 {
 	ide_startstop_t startstop;
 	struct cdrom_info *info = drive->driver_data;
@@ -740,9 +737,9 @@
 
 	if (info->dma) {
 		if (info->cmd == READ)
-			info->dma = !drive->channel->dmaproc(ide_dma_read, drive);
+			info->dma = !drive->channel->udma(ide_dma_read, drive, rq);
 		else if (info->cmd == WRITE)
-			info->dma = !drive->channel->dmaproc(ide_dma_write, drive);
+			info->dma = !drive->channel->udma(ide_dma_write, drive, rq);
 		else
 			printk("ide-cd: DMA set, but not allowed\n");
 	}
@@ -758,16 +755,15 @@
 		OUT_BYTE (drive->ctl, IDE_CONTROL_REG);
 
 	if (info->dma)
-		drive->channel->dmaproc(ide_dma_begin, drive);
+		drive->channel->udma(ide_dma_begin, drive, NULL);
 
 	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
-		BUG_ON(HWGROUP(drive)->handler);
-		ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry);
+		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 */
-		return (*handler) (drive);
+		return handler(drive, rq);
 	}
 }
 
@@ -776,9 +772,10 @@
  * already been prepared by cdrom_start_packet_command.  "handler" is the
  * interrupt handler to call when the command completes or there's data ready.
  */
-static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive,
+static ide_startstop_t cdrom_transfer_packet_command(struct ata_device *drive,
+		struct request *rq,
 		unsigned char *cmd, unsigned long timeout,
-		ide_handler_t *handler)
+		ata_handler_t handler)
 {
 	ide_startstop_t startstop;
 
@@ -788,7 +785,7 @@
 		int stat_dum;
 
 		/* Check for errors. */
-		if (cdrom_decode_status(&startstop, drive, DRQ_STAT, &stat_dum))
+		if (cdrom_decode_status(&startstop, drive, rq, DRQ_STAT, &stat_dum))
 			return startstop;
 	} else {
 		/* Otherwise, we must wait for DRQ to get set. */
@@ -797,7 +794,6 @@
 	}
 
 	/* Arm the interrupt handler. */
-	BUG_ON(HWGROUP(drive)->handler);
 	ide_set_handler(drive, handler, timeout, cdrom_timer_expiry);
 
 	/* Send the command to the device. */
@@ -861,7 +857,7 @@
  * ok; nonzero if the request has been terminated.
  */
 static inline
-int cdrom_read_check_ireason (ide_drive_t *drive, int len, int ireason)
+int cdrom_read_check_ireason(struct ata_device *drive, struct request *rq, int len, int ireason)
 {
 	ireason &= 3;
 	if (ireason == 2) return 0;
@@ -891,14 +887,14 @@
 			drive->name, ireason);
 	}
 
-	cdrom_end_request(drive, 0);
+	cdrom_end_request(drive, rq, 0);
 	return -1;
 }
 
 /*
  * Interrupt routine.  Called when a read request has completed.
  */
-static ide_startstop_t cdrom_read_intr(ide_drive_t *drive)
+static ide_startstop_t cdrom_read_intr(struct ata_device *drive, struct request *rq)
 {
 	int stat;
 	int ireason, len, sectors_to_transfer, nskip;
@@ -906,21 +902,19 @@
 	int dma = info->dma, dma_error = 0;
 	ide_startstop_t startstop;
 
-	struct request *rq = HWGROUP(drive)->rq;
-
 	/* Check for errors. */
 	if (dma) {
 		info->dma = 0;
-		if ((dma_error = drive->channel->dmaproc(ide_dma_end, drive)))
-			drive->channel->dmaproc(ide_dma_off, drive);
+		if ((dma_error = drive->channel->udma(ide_dma_end, drive, NULL)))
+			drive->channel->udma(ide_dma_off, drive, NULL);
 	}
 
-	if (cdrom_decode_status (&startstop, drive, 0, &stat))
+	if (cdrom_decode_status(&startstop, drive, rq, 0, &stat))
 		return startstop;
 
 	if (dma) {
 		if (!dma_error) {
-			__ide_end_request(drive, 1, rq->nr_sectors);
+			__ide_end_request(drive, rq, 1, rq->nr_sectors);
 			return ide_stopped;
 		} else
 			return ide_error (drive, "dma error", stat);
@@ -937,14 +931,14 @@
 		if (rq->current_nr_sectors > 0) {
 			printk ("%s: cdrom_read_intr: data underrun (%u blocks)\n",
 				drive->name, rq->current_nr_sectors);
-			cdrom_end_request(drive, 0);
+			cdrom_end_request(drive, rq, 0);
 		} else
-			cdrom_end_request(drive, 1);
+			cdrom_end_request(drive, rq, 1);
 		return ide_stopped;
 	}
 
 	/* Check that the drive is expecting to do the same thing we are. */
-	if (cdrom_read_check_ireason (drive, len, ireason))
+	if (cdrom_read_check_ireason(drive, rq, len, ireason))
 		return ide_stopped;
 
 	/* Assume that the drive will always provide data in multiples
@@ -959,7 +953,7 @@
 			printk ("  Trying to limit transfer sizes\n");
 			CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1;
 		}
-		cdrom_end_request(drive, 0);
+		cdrom_end_request(drive, rq, 0);
 		return ide_stopped;
 	}
 
@@ -987,7 +981,7 @@
 		/* If we've filled the present buffer but there's another
 		   chained buffer after it, move on. */
 		if (rq->current_nr_sectors == 0 && rq->nr_sectors)
-			cdrom_end_request(drive, 1);
+			cdrom_end_request(drive, rq, 1);
 
 		/* If the buffers are full, cache the rest of the data in our
 		   internal buffer. */
@@ -1015,10 +1009,8 @@
 		}
 	}
 
-	/* Done moving data!
-	   Wait for another interrupt. */
-	BUG_ON(HWGROUP(drive)->handler);
-	ide_set_handler(drive, &cdrom_read_intr, WAIT_CMD, NULL);
+	/* Done moving data! Wait for another interrupt. */
+	ide_set_handler(drive, cdrom_read_intr, WAIT_CMD, NULL);
 
 	return ide_started;
 }
@@ -1027,10 +1019,9 @@
  * Try to satisfy some of the current read request from our cached data.
  * Returns nonzero if the request has been completed, zero otherwise.
  */
-static int cdrom_read_from_buffer (ide_drive_t *drive)
+static int cdrom_read_from_buffer(struct ata_device *drive, struct request *rq)
 {
 	struct cdrom_info *info = drive->driver_data;
-	struct request *rq = HWGROUP(drive)->rq;
 
 	/* Can't do anything if there's no buffer. */
 	if (info->buffer == NULL) return 0;
@@ -1041,7 +1032,7 @@
 	       rq->sector >= info->sector_buffered &&
 	       rq->sector < info->sector_buffered + info->nsectors_buffered) {
 		if (rq->current_nr_sectors == 0)
-			cdrom_end_request(drive, 1);
+			cdrom_end_request(drive, rq, 1);
 
 		memcpy (rq->buffer,
 			info->buffer +
@@ -1056,13 +1047,13 @@
 	/* If we've satisfied the current request,
 	   terminate it successfully. */
 	if (rq->nr_sectors == 0) {
-		cdrom_end_request(drive, 1);
+		cdrom_end_request(drive, rq, 1);
 		return -1;
 	}
 
 	/* Move on to the next buffer if needed. */
 	if (rq->current_nr_sectors == 0)
-		cdrom_end_request(drive, 1);
+		cdrom_end_request(drive, rq, 1);
 
 	/* If this condition does not hold, then the kluge i use to
 	   represent the number of sectors to skip at the start of a transfer
@@ -1070,9 +1061,9 @@
 	   paranoid and check. */
 	if (rq->current_nr_sectors < bio_sectors(rq->bio) &&
 	    (rq->sector % SECTORS_PER_FRAME) != 0) {
-		printk ("%s: cdrom_read_from_buffer: buffer botch (%ld)\n",
-			drive->name, rq->sector);
-		cdrom_end_request(drive, 0);
+		printk ("%s: %s: buffer botch (%ld)\n",
+			drive->name, __FUNCTION__, rq->sector);
+		cdrom_end_request(drive, rq, 0);
 		return -1;
 	}
 
@@ -1084,9 +1075,8 @@
  * directly from cdrom_start_read.  However, for drq_interrupt devices, it is
  * called from an interrupt when the drive is ready to accept the command.
  */
-static ide_startstop_t cdrom_start_read_continuation(ide_drive_t *drive)
+static ide_startstop_t cdrom_start_read_continuation(struct ata_device *drive, struct request *rq)
 {
-	struct request *rq = HWGROUP(drive)->rq;
 	int nsect, sector, nframes, frame, nskip;
 
 	/* Number of sectors to transfer. */
@@ -1107,9 +1097,9 @@
 		/* Sanity check... */
 		if (rq->current_nr_sectors != bio_sectors(rq->bio) &&
 			(rq->sector % CD_FRAMESIZE != 0)) {
-			printk ("%s: cdrom_start_read_continuation: buffer botch (%u)\n",
-				drive->name, rq->current_nr_sectors);
-			cdrom_end_request(drive, 0);
+			printk ("%s: %s: buffer botch (%u)\n",
+				drive->name, __FUNCTION__, rq->current_nr_sectors);
+			cdrom_end_request(drive, rq, 0);
 			return ide_stopped;
 		}
 		sector -= nskip;
@@ -1128,7 +1118,7 @@
 		(65534 / CD_FRAMESIZE) : 65535);
 
 	/* Send the command to the drive and return. */
-	return cdrom_transfer_packet_command(drive, rq->cmd, WAIT_CMD, &cdrom_read_intr);
+	return cdrom_transfer_packet_command(drive, rq, rq->cmd, WAIT_CMD, &cdrom_read_intr);
 }
 
 
@@ -1136,14 +1126,14 @@
 #define IDECD_SEEK_TIMER	(5 * WAIT_MIN_SLEEP)	/* 100 ms */
 #define IDECD_SEEK_TIMEOUT     WAIT_CMD			/* 10 sec */
 
-static ide_startstop_t cdrom_seek_intr (ide_drive_t *drive)
+static ide_startstop_t cdrom_seek_intr(struct ata_device *drive, struct request *rq)
 {
 	struct cdrom_info *info = drive->driver_data;
 	int stat;
 	static int retry = 10;
 	ide_startstop_t startstop;
 
-	if (cdrom_decode_status (&startstop, drive, 0, &stat))
+	if (cdrom_decode_status (&startstop, drive, rq, 0, &stat))
 		return startstop;
 	CDROM_CONFIG_FLAGS(drive)->seeking = 1;
 
@@ -1162,10 +1152,9 @@
 	return ide_stopped;
 }
 
-static ide_startstop_t cdrom_start_seek_continuation(struct ata_device *drive)
+static ide_startstop_t cdrom_start_seek_continuation(struct ata_device *drive, struct request *rq)
 {
 	unsigned char cmd[CDROM_PACKET_SIZE];
-	struct request *rq = HWGROUP(drive)->rq;
 	sector_t sector;
 	int frame, nskip;
 
@@ -1179,17 +1168,17 @@
 	cmd[0] = GPCMD_SEEK;
 	put_unaligned(cpu_to_be32(frame), (unsigned int *) &cmd[2]);
 
-	return cdrom_transfer_packet_command(drive, cmd, WAIT_CMD, &cdrom_seek_intr);
+	return cdrom_transfer_packet_command(drive, rq, cmd, WAIT_CMD, &cdrom_seek_intr);
 }
 
-static ide_startstop_t cdrom_start_seek(struct ata_device *drive, sector_t block)
+static ide_startstop_t cdrom_start_seek(struct ata_device *drive, struct request *rq, sector_t block)
 {
 	struct cdrom_info *info = drive->driver_data;
 
 	info->dma = 0;
 	info->cmd = 0;
 	info->start_seek = jiffies;
-	return cdrom_start_packet_command(drive, 0, cdrom_start_seek_continuation);
+	return cdrom_start_packet_command(drive, rq, 0, cdrom_start_seek_continuation);
 }
 
 /*
@@ -1214,15 +1203,14 @@
 /*
  * Start a read request from the CD-ROM.
  */
-static ide_startstop_t cdrom_start_read(struct ata_device *drive, sector_t block)
+static ide_startstop_t cdrom_start_read(struct ata_device *drive, struct request *rq, sector_t block)
 {
 	struct cdrom_info *info = drive->driver_data;
-	struct request *rq = HWGROUP(drive)->rq;
 
 	restore_request(rq);
 
 	/* Satisfy whatever we can of this request from our cached sector. */
-	if (cdrom_read_from_buffer(drive))
+	if (cdrom_read_from_buffer(drive, rq))
 		return ide_stopped;
 
 	blk_attempt_remerge(&drive->queue, rq);
@@ -1239,7 +1227,7 @@
 
 	info->cmd = READ;
 	/* Start sending the read request to the drive. */
-	return cdrom_start_packet_command(drive, 32768, cdrom_start_read_continuation);
+	return cdrom_start_packet_command(drive, rq, 32768, cdrom_start_read_continuation);
 }
 
 /****************************************************************************
@@ -1247,17 +1235,16 @@
  */
 
 /* Interrupt routine for packet command completion. */
-static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive)
+static ide_startstop_t cdrom_pc_intr(struct ata_device *drive, struct request *rq)
 {
 	int ireason, len, stat, thislen;
-	struct request *rq = HWGROUP(drive)->rq;
 
 	/* FIXME --mdcki */
 	struct packet_command *pc = (struct packet_command *) rq->special;
 	ide_startstop_t startstop;
 
 	/* Check for errors. */
-	if (cdrom_decode_status (&startstop, drive, 0, &stat))
+	if (cdrom_decode_status (&startstop, drive, rq, 0, &stat))
 		return startstop;
 
 	/* Read the interrupt reason and the transfer length. */
@@ -1279,7 +1266,7 @@
 		}
 
 		if (pc->buflen == 0)
-			cdrom_end_request(drive, 1);
+			cdrom_end_request(drive, rq, 1);
 		else {
 			/* Comment this out, because this always happens
 			   right after a reset occurs, and it is annoying to
@@ -1289,7 +1276,7 @@
 				drive->name, pc->buflen);
 			*/
 			pc->stat = 1;
-			cdrom_end_request(drive, 1);
+			cdrom_end_request(drive, rq, 1);
 		}
 		return ide_stopped;
 	}
@@ -1341,15 +1328,13 @@
 	}
 
 	/* Now we wait for another interrupt. */
+	ide_set_handler(drive, cdrom_pc_intr, WAIT_CMD, cdrom_timer_expiry);
 
-	BUG_ON(HWGROUP(drive)->handler);
-	ide_set_handler (drive, &cdrom_pc_intr, WAIT_CMD, cdrom_timer_expiry);
 	return ide_started;
 }
 
-static ide_startstop_t cdrom_do_pc_continuation(ide_drive_t *drive)
+static ide_startstop_t cdrom_do_pc_continuation(struct ata_device *drive, struct request *rq)
 {
-	struct request *rq = HWGROUP(drive)->rq;
 	unsigned long timeout;
 
 	/* FIXME --mdcki */
@@ -1361,13 +1346,12 @@
 		timeout = WAIT_CMD;
 
 	/* Send the command to the drive and return. */
-	return cdrom_transfer_packet_command(drive, rq->cmd, timeout, &cdrom_pc_intr);
+	return cdrom_transfer_packet_command(drive, rq, rq->cmd, timeout, &cdrom_pc_intr);
 }
 
-static ide_startstop_t cdrom_do_packet_command (ide_drive_t *drive)
+static ide_startstop_t cdrom_do_packet_command(struct ata_device *drive, struct request *rq)
 {
 	int len;
-	struct request *rq = HWGROUP(drive)->rq;
 
 	/* FIXME --mdcki */
 	struct packet_command *pc = (struct packet_command *) rq->special;
@@ -1379,7 +1363,7 @@
 	len = pc->buflen;
 
 	/* Start sending the command to the drive. */
-	return cdrom_start_packet_command (drive, len, cdrom_do_pc_continuation);
+	return cdrom_start_packet_command (drive, rq, len, cdrom_do_pc_continuation);
 }
 
 
@@ -1455,7 +1439,8 @@
 /*
  * Write handling
  */
-static inline int cdrom_write_check_ireason(ide_drive_t *drive, int len, int ireason)
+static inline int cdrom_write_check_ireason(struct ata_device *drive, struct request *rq,
+	int len, int ireason)
 {
 	/* Two notes about IDE interrupt reason here - 0 means that
 	 * the drive wants to receive data from us, 2 means that
@@ -1481,29 +1466,27 @@
 			drive->name, ireason);
 	}
 
-	cdrom_end_request(drive, 0);
+	cdrom_end_request(drive, rq, 0);
 	return 1;
 }
 
-static ide_startstop_t cdrom_write_intr(ide_drive_t *drive)
+static ide_startstop_t cdrom_write_intr(struct ata_device *drive, struct request *rq)
 {
 	int stat, ireason, len, sectors_to_transfer, uptodate;
 	struct cdrom_info *info = drive->driver_data;
 	int dma_error = 0, dma = info->dma;
 	ide_startstop_t startstop;
 
-	struct request *rq = HWGROUP(drive)->rq;
-
 	/* Check for errors. */
 	if (dma) {
 		info->dma = 0;
-		if ((dma_error = drive->channel->dmaproc(ide_dma_end, drive))) {
+		if ((dma_error = drive->channel->udma(ide_dma_end, drive, NULL))) {
 			printk("ide-cd: write dma error\n");
-			drive->channel->dmaproc(ide_dma_off, drive);
+			drive->channel->udma(ide_dma_off, drive, NULL);
 		}
 	}
 
-	if (cdrom_decode_status(&startstop, drive, 0, &stat)) {
+	if (cdrom_decode_status(&startstop, drive, rq, 0, &stat)) {
 		printk("ide-cd: write_intr decode_status bad\n");
 		return startstop;
 	}
@@ -1515,8 +1498,7 @@
 		if (dma_error)
 			return ide_error(drive, "dma error", stat);
 
-		rq = HWGROUP(drive)->rq;
-		__ide_end_request(drive, 1, rq->nr_sectors);
+		__ide_end_request(drive, rq, 1, rq->nr_sectors);
 		return ide_stopped;
 	}
 
@@ -1535,13 +1517,13 @@
 			drive->name, rq->current_nr_sectors);
 			uptodate = 0;
 		}
-		cdrom_end_request(drive, uptodate);
+		cdrom_end_request(drive, rq, uptodate);
 		return ide_stopped;
 	}
 
 	/* Check that the drive is expecting to do the same thing we are. */
 	if (ireason & 3)
-		if (cdrom_write_check_ireason(drive, len, ireason))
+		if (cdrom_write_check_ireason(drive, rq, len, ireason))
 			return ide_stopped;
 
 	sectors_to_transfer = len / SECTOR_SIZE;
@@ -1576,23 +1558,21 @@
 		 * current buffer complete, move on
 		 */
 		if (rq->current_nr_sectors == 0 && rq->nr_sectors)
-			cdrom_end_request(drive, 1);
+			cdrom_end_request(drive, rq, 1);
 	}
 
 	/* re-arm handler */
-	BUG_ON(HWGROUP(drive)->handler);
-	ide_set_handler(drive, &cdrom_write_intr, 5 * WAIT_CMD, NULL);
+	ide_set_handler(drive, cdrom_write_intr, 5 * WAIT_CMD, NULL);
+
 	return ide_started;
 }
 
-static ide_startstop_t cdrom_start_write_cont(ide_drive_t *drive)
+static ide_startstop_t cdrom_start_write_cont(struct ata_device *drive, struct request *rq)
 {
-	struct request *rq = HWGROUP(drive)->rq;
-
-	return cdrom_transfer_packet_command(drive, rq->cmd, 2 * WAIT_CMD, cdrom_write_intr);
+	return cdrom_transfer_packet_command(drive, rq, rq->cmd, 2 * WAIT_CMD, cdrom_write_intr);
 }
 
-static ide_startstop_t cdrom_start_write(ide_drive_t *drive, struct request *rq)
+static ide_startstop_t cdrom_start_write(struct ata_device *drive, struct request *rq)
 {
 	struct cdrom_info *info = drive->driver_data;
 
@@ -1600,7 +1580,7 @@
 	 * writes *must* be 2kB frame aligned
 	 */
 	if ((rq->nr_sectors & 3) || (rq->sector & 3)) {
-		cdrom_end_request(drive, 0);
+		cdrom_end_request(drive, rq, 0);
 		return ide_stopped;
 	}
 
@@ -1620,7 +1600,7 @@
 	info->cmd = WRITE;
 
 	/* Start sending the read request to the drive. */
-	return cdrom_start_packet_command(drive, 32768, cdrom_start_write_cont);
+	return cdrom_start_packet_command(drive, rq, 32768, cdrom_start_write_cont);
 }
 
 #define IDE_LARGE_SEEK(b1,b2,t)	(((b1) > (b2) + (t)) || ((b2) > (b1) + (t)))
@@ -1649,17 +1629,17 @@
 			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);
+			action = cdrom_start_seek(drive, rq, block);
 		else {
 			if (rq_data_dir(rq) == READ)
-				action = cdrom_start_read(drive, block);
+				action = cdrom_start_read(drive, rq, block);
 			else
 				action = cdrom_start_write(drive, rq);
 		}
 		info->last_block = block;
 		return action;
 	} else if (rq->flags & (REQ_PC | REQ_SENSE)) {
-		return cdrom_do_packet_command(drive);
+		return cdrom_do_packet_command(drive, rq);
 	} else if (rq->flags & REQ_SPECIAL) {
 		/*
 		 * FIXME: Kill REQ_SEPCIAL and replace it with commands queued
@@ -1668,7 +1648,7 @@
 		 * right now this can only be a reset...
 		 */
 
-		cdrom_end_request(drive, 1);
+		cdrom_end_request(drive, rq, 1);
 		return ide_stopped;
 	} else if (rq->flags & REQ_BLOCK_PC) {
 		struct packet_command pc;
@@ -1681,7 +1661,7 @@
 		/* FIXME --mdcki */
 		rq->special = (char *) &pc;
 
-		startstop = cdrom_do_packet_command(drive);
+		startstop = cdrom_do_packet_command(drive, rq);
 		if (pc.stat)
 			++rq->errors;
 
@@ -1689,7 +1669,7 @@
 	}
 
 	blk_dump_rq_flags(rq, "ide-cd bad flags");
-	cdrom_end_request(drive, 0);
+	cdrom_end_request(drive, rq, 0);
 	return ide_stopped;
 }
 
@@ -2672,8 +2652,8 @@
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (drive->using_dma)
-		(void) drive->channel->dmaproc(ide_dma_verbose, drive);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
+		(void) drive->channel->udma(ide_dma_verbose, drive, NULL);
+#endif
 	printk("\n");
 
 	return nslots;
diff -Nru a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
--- a/drivers/ide/ide-disk.c	Tue Apr 30 17:10:23 2002
+++ b/drivers/ide/ide-disk.c	Tue Apr 30 17:10:23 2002
@@ -275,7 +275,7 @@
 
 	if (!(rq->flags & REQ_CMD)) {
 		blk_dump_rq_flags(rq, "idedisk_do_request - bad command");
-		ide_end_request(drive, 0);
+		ide_end_request(drive, rq, 0);
 		return ide_stopped;
 	}
 
@@ -562,17 +562,17 @@
  */
 static int set_multcount(ide_drive_t *drive, int arg)
 {
-	struct ata_taskfile args;
+	struct request rq;
 
 	if (drive->special_cmd & ATA_SPECIAL_MMODE)
 		return -EBUSY;
 
-	memset(&args, 0, sizeof(args));
+	ide_init_drive_cmd(&rq);
 
 	drive->mult_req = arg;
 	drive->special_cmd |= ATA_SPECIAL_MMODE;
 
-	ide_raw_taskfile(drive, &args, NULL);
+	ide_do_drive_cmd (drive, &rq, ide_wait);
 
 	return (drive->mult_count == arg) ? 0 : -EIO;
 }
@@ -1050,7 +1050,7 @@
 	       drive->bios_cyl, drive->bios_head, drive->bios_sect);
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (drive->using_dma)
-		(void) drive->channel->dmaproc(ide_dma_verbose, drive);
+		(void) drive->channel->udma(ide_dma_verbose, drive, NULL);
 #endif
 	printk("\n");
 
diff -Nru a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
--- a/drivers/ide/ide-dma.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/ide/ide-dma.c	Tue Apr 30 17:10:25 2002
@@ -5,7 +5,7 @@
  *  May be copied or modified under the terms of the GNU General Public License
  *
  *  Special Thanks to Mark for his Six years of work.
-*
+ *
  * This module provides support for the bus-master IDE DMA functions
  * of various PCI chipsets, including the Intel PIIX (i82371FB for
  * the 430 FX chipset), the PIIX3 (i82371SB for the 430 HX/VX and
@@ -194,17 +194,14 @@
 /*
  * dma_intr() is the handler for disk read/write DMA interrupts
  */
-ide_startstop_t ide_dma_intr (ide_drive_t *drive)
+ide_startstop_t ide_dma_intr(struct ata_device *drive, struct request *rq)
 {
 	byte stat, dma_stat;
 
-	dma_stat = drive->channel->dmaproc(ide_dma_end, drive);
-	stat = GET_STAT();			/* get drive status */
-	if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
+	dma_stat = drive->channel->udma(ide_dma_end, drive, rq);
+	if (OK_STAT(stat = GET_STAT(),DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
 		if (!dma_stat) {
-			struct request *rq = HWGROUP(drive)->rq;
-
-			__ide_end_request(drive, 1, rq->nr_sectors);
+			__ide_end_request(drive, rq, 1, rq->nr_sectors);
 			return ide_stopped;
 		}
 		printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n",
@@ -461,38 +458,39 @@
 
 	if (id && (id->capability & 1) && hwif->autodma && config_allows_dma) {
 		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive))
-			return hwif->dmaproc(ide_dma_off, drive);
+		if (ide_dmaproc(ide_dma_bad_drive, drive, NULL))
+			return hwif->udma(ide_dma_off, drive, NULL);
 
 		/* Enable DMA on any drive that has UltraDMA (mode 6/7/?) enabled */
 		if ((id->field_valid & 4) && (eighty_ninty_three(drive)))
 			if ((id->dma_ultra & (id->dma_ultra >> 14) & 2))
-				return hwif->dmaproc(ide_dma_on, drive);
+				return hwif->udma(ide_dma_on, drive, NULL);
 		/* Enable DMA on any drive that has UltraDMA (mode 3/4/5) enabled */
 		if ((id->field_valid & 4) && (eighty_ninty_three(drive)))
 			if ((id->dma_ultra & (id->dma_ultra >> 11) & 7))
-				return hwif->dmaproc(ide_dma_on, drive);
+				return hwif->udma(ide_dma_on, drive, NULL);
 		/* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */
 		if (id->field_valid & 4)	/* UltraDMA */
 			if ((id->dma_ultra & (id->dma_ultra >> 8) & 7))
-				return hwif->dmaproc(ide_dma_on, drive);
+				return hwif->udma(ide_dma_on, drive, NULL);
 		/* Enable DMA on any drive that has mode2 DMA (multi or single) enabled */
 		if (id->field_valid & 2)	/* regular DMA */
 			if ((id->dma_mword & 0x404) == 0x404 || (id->dma_1word & 0x404) == 0x404)
-				return hwif->dmaproc(ide_dma_on, drive);
+				return hwif->udma(ide_dma_on, drive, NULL);
 		/* Consult the list of known "good" drives */
-		if (ide_dmaproc(ide_dma_good_drive, drive))
-			return hwif->dmaproc(ide_dma_on, drive);
+		if (ide_dmaproc(ide_dma_good_drive, drive, NULL))
+			return hwif->udma(ide_dma_on, drive, NULL);
 	}
-	return hwif->dmaproc(ide_dma_off_quietly, drive);
+	return hwif->udma(ide_dma_off_quietly, drive, NULL);
 }
 
 /*
  * 1 dma-ing, 2 error, 4 intr
  */
-static int dma_timer_expiry(ide_drive_t *drive)
+static int dma_timer_expiry(struct ata_device *drive, struct request *__rq)
 {
-	byte dma_stat = inb(drive->channel->dma_base+2);
+	/* FIXME: What's that? */
+	u8 dma_stat = inb(drive->channel->dma_base+2);
 
 #ifdef DEBUG
 	printk("%s: dma_timer_expiry: dma status == 0x%02x\n", drive->name, dma_stat);
@@ -503,7 +501,7 @@
 #endif
 
 	if (dma_stat & 2) {	/* ERROR */
-		byte stat = GET_STAT();
+		u8 stat = GET_STAT();
 		return ide_error(drive, "dma_timer_expiry", stat);
 	}
 	if (dma_stat & 1)	/* DMAing */
@@ -526,7 +524,7 @@
 }
 
 /*
- * ide_dmaproc() initiates/aborts DMA read/write operations on a drive.
+ * This initiates/aborts DMA read/write operations on a drive.
  *
  * The caller is assumed to have selected the drive and programmed the drive's
  * sector address using CHS or LBA.  All that remains is to prepare for DMA
@@ -541,7 +539,7 @@
  * the caller should revert to PIO for the current request.
  * May also be invoked from trm290.c
  */
-int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+int ide_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq)
 {
 	struct ata_channel *hwif = drive->channel;
 	unsigned long dma_base = hwif->dma_base;
@@ -579,11 +577,9 @@
 			if (drive->type != ATA_DISK)
 				return 0;
 
-			BUG_ON(HWGROUP(drive)->handler);
-			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, dma_timer_expiry);	/* issue cmd to drive */
-			if ((HWGROUP(drive)->rq->flags & REQ_DRIVE_ACB) &&
-			    (drive->addressing == 1)) {
-				struct ata_taskfile *args = HWGROUP(drive)->rq->special;
+			ide_set_handler(drive, ide_dma_intr, WAIT_CMD, dma_timer_expiry);	/* issue cmd to drive */
+			if ((rq->flags & REQ_DRIVE_ACB) && (drive->addressing == 1)) {
+				struct ata_taskfile *args = rq->special;
 
 				OUT_BYTE(args->taskfile.command, IDE_COMMAND_REG);
 			} else if (drive->addressing) {
@@ -591,7 +587,7 @@
 			} else {
 				OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
 			}
-			return drive->channel->dmaproc(ide_dma_begin, drive);
+			return drive->channel->udma(ide_dma_begin, drive, NULL);
 		case ide_dma_begin:
 			/* Note that this is done *after* the cmd has
 			 * been issued to the drive, as per the BM-IDE spec.
@@ -685,7 +681,7 @@
 		goto dma_alloc_failure;
 	}
 
-	hwif->dmaproc = &ide_dmaproc;
+	hwif->udma = ide_dmaproc;
 
 	if (hwif->chipset != ide_trm290) {
 		byte dma_stat = inb(dma_base+2);
diff -Nru a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
--- a/drivers/ide/ide-floppy.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/ide/ide-floppy.c	Tue Apr 30 17:10:25 2002
@@ -152,10 +152,9 @@
 	int buffer_size;			/* Size of our data buffer */
 	char *b_data;				/* Pointer which runs on the buffers */
 	int b_count;				/* Missing/Available data on the current buffer */
-	struct request *rq;			/* The corresponding request */
 	byte *buffer;				/* Data buffer */
 	byte *current_position;			/* Pointer into the above buffer */
-	void (*callback) (ide_drive_t *);	/* Called when this packet command is completed */
+	void (*callback) (struct ata_device *, struct request *);	/* Called when this packet command is completed */
 	byte pc_buffer[IDEFLOPPY_PC_BUFFER_SIZE];	/* Temporary buffer */
 	unsigned long flags;			/* Status/Action bit flags: long for set_bit */
 } idefloppy_pc_t;
@@ -669,10 +668,9 @@
  *	For read/write requests, we will call ide_end_request to pass to the
  *	next buffer.
  */
-static int idefloppy_end_request(ide_drive_t *drive, int uptodate)
+static int idefloppy_end_request(struct ata_device *drive, struct request *rq, int uptodate)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	struct request *rq = HWGROUP(drive)->rq;
 	int error;
 
 #if IDEFLOPPY_DEBUG_LOG
@@ -690,7 +688,7 @@
 	if (!rq)
 		return 0;
 	if (!(rq->flags & IDEFLOPPY_RQ)) {
-		ide_end_request(drive, uptodate);
+		ide_end_request(drive, rq, uptodate);
 		return 0;
 	}
 	rq->errors = error;
@@ -699,9 +697,9 @@
 	return 0;
 }
 
-static void idefloppy_input_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, unsigned int bcount)
+static void idefloppy_input_buffers(struct ata_device *drive, struct request *rq,
+	idefloppy_pc_t *pc, unsigned int bcount)
 {
-	struct request *rq = pc->rq;
 	struct bio *bio = rq->bio;
 	int count;
 
@@ -709,12 +707,12 @@
 		if (pc->b_count == bio->bi_size) {
 			rq->sector += rq->current_nr_sectors;
 			rq->nr_sectors -= rq->current_nr_sectors;
-			idefloppy_end_request(drive, 1);
+			idefloppy_end_request(drive, rq, 1);
 			if ((bio = rq->bio) != NULL)
 				pc->b_count = 0;
 		}
 		if (bio == NULL) {
-			printk (KERN_ERR "%s: bio == NULL in idefloppy_input_buffers, bcount == %d\n", drive->name, bcount);
+			printk (KERN_ERR "%s: bio == NULL in %s, bcount == %d\n", drive->name, __FUNCTION__, bcount);
 			idefloppy_discard_data (drive, bcount);
 			return;
 		}
@@ -724,17 +722,17 @@
 	}
 }
 
-static void idefloppy_output_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, unsigned int bcount)
+static void idefloppy_output_buffers(struct ata_device *drive, struct request *rq,
+	idefloppy_pc_t *pc, unsigned int bcount)
 {
-	struct request *rq = pc->rq;
 	struct bio *bio = rq->bio;
 	int count;
-	
+
 	while (bcount) {
 		if (!pc->b_count) {
 			rq->sector += rq->current_nr_sectors;
 			rq->nr_sectors -= rq->current_nr_sectors;
-			idefloppy_end_request(drive, 1);
+			idefloppy_end_request(drive, rq, 1);
 			if ((bio = rq->bio) != NULL) {
 				pc->b_data = bio_data(bio);
 				pc->b_count = bio->bi_size;
@@ -752,13 +750,13 @@
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-static void idefloppy_update_buffers (ide_drive_t *drive, idefloppy_pc_t *pc)
+static void idefloppy_update_buffers (struct ata_device *drive, struct request *rq,
+	idefloppy_pc_t *pc)
 {
-	struct request *rq = pc->rq;
 	struct bio *bio = rq->bio;
 
 	while ((bio = rq->bio) != NULL)
-		idefloppy_end_request(drive, 1);
+		idefloppy_end_request(drive, rq, 1);
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
@@ -812,7 +810,7 @@
 #endif /* IDEFLOPPY_DEBUG_LOG */
 }
 
-static void idefloppy_request_sense_callback (ide_drive_t *drive)
+static void idefloppy_request_sense_callback(struct ata_device *drive, struct request *rq)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
@@ -821,25 +819,25 @@
 #endif /* IDEFLOPPY_DEBUG_LOG */
 	if (!floppy->pc->error) {
 		idefloppy_analyze_error (drive,(idefloppy_request_sense_result_t *) floppy->pc->buffer);
-		idefloppy_end_request(drive, 1);
+		idefloppy_end_request(drive, rq, 1);
 	} else {
 		printk (KERN_ERR "Error in REQUEST SENSE itself - Aborting request!\n");
-		idefloppy_end_request(drive, 0);
+		idefloppy_end_request(drive, rq, 0);
 	}
 }
 
 /*
  *	General packet command callback function.
  */
-static void idefloppy_pc_callback (ide_drive_t *drive)
+static void idefloppy_pc_callback(struct ata_device *drive, struct request *rq)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	
+
 #if IDEFLOPPY_DEBUG_LOG
 	printk (KERN_INFO "ide-floppy: Reached idefloppy_pc_callback\n");
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
-	idefloppy_end_request(drive, floppy->pc->error ? 0:1);
+	idefloppy_end_request(drive, rq, floppy->pc->error ? 0:1);
 }
 
 /*
@@ -854,7 +852,7 @@
 	pc->buffer = pc->pc_buffer;
 	pc->buffer_size = IDEFLOPPY_PC_BUFFER_SIZE;
 	pc->b_data = NULL;
-	pc->callback = &idefloppy_pc_callback;
+	pc->callback = idefloppy_pc_callback;
 }
 
 static void idefloppy_create_request_sense_cmd (idefloppy_pc_t *pc)
@@ -888,33 +886,32 @@
  *	idefloppy_pc_intr is the usual interrupt handler which will be called
  *	during a packet command.
  */
-static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
+static ide_startstop_t idefloppy_pc_intr(struct ata_device *drive, struct request *rq)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	idefloppy_status_reg_t status;
 	idefloppy_bcount_reg_t bcount;
 	idefloppy_ireason_reg_t ireason;
 	idefloppy_pc_t *pc=floppy->pc;
-	struct request *rq = pc->rq;
 	unsigned int temp;
 
 #if IDEFLOPPY_DEBUG_LOG
 	printk (KERN_INFO "ide-floppy: Reached idefloppy_pc_intr interrupt handler\n");
-#endif /* IDEFLOPPY_DEBUG_LOG */	
+#endif
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
-		if (drive->channel->dmaproc(ide_dma_end, drive)) {
+		if (drive->channel->udma(ide_dma_end, drive, NULL)) {
 			set_bit (PC_DMA_ERROR, &pc->flags);
 		} else {
 			pc->actually_transferred=pc->request_transfer;
-			idefloppy_update_buffers (drive, pc);
+			idefloppy_update_buffers(drive, rq, pc);
 		}
-#if IDEFLOPPY_DEBUG_LOG
+# if IDEFLOPPY_DEBUG_LOG
 		printk (KERN_INFO "ide-floppy: DMA finished\n");
-#endif /* IDEFLOPPY_DEBUG_LOG */
+# endif
 	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
+#endif
 
 	status.all = GET_STAT();					/* Clear the interrupt */
 
@@ -941,13 +938,13 @@
 		pc->error = 0;
 		if (floppy->failed_pc == pc)
 			floppy->failed_pc=NULL;
-		pc->callback(drive);			/* Command finished - Call the callback function */
+		pc->callback(drive, rq);    /* Command finished - Call the callback function */
 		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");
-		drive->channel->dmaproc(ide_dma_off, drive);
+		drive->channel->udma(ide_dma_off, drive, NULL);
 		return ide_stopped;
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
@@ -970,8 +967,7 @@
 			if (temp > pc->buffer_size) {
 				printk (KERN_ERR "ide-floppy: The floppy wants to send us more data than expected - discarding data\n");
 				idefloppy_discard_data (drive,bcount.all);
-				BUG_ON(HWGROUP(drive)->handler);
-				ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL);
+				ide_set_handler(drive, idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL);
 				return ide_started;
 			}
 #if IDEFLOPPY_DEBUG_LOG
@@ -983,18 +979,17 @@
 		if (pc->buffer != NULL)
 			atapi_write(drive,pc->current_position,bcount.all);	/* Write the current buffer */
 		else
-			idefloppy_output_buffers (drive, pc, bcount.all);
+			idefloppy_output_buffers(drive, rq, pc, bcount.all);
 	} else {
 		if (pc->buffer != NULL)
 			atapi_read(drive,pc->current_position,bcount.all);	/* Read the current buffer */
 		else
-			idefloppy_input_buffers (drive, pc, bcount.all);
+			idefloppy_input_buffers (drive, rq, pc, bcount.all);
 	}
 	pc->actually_transferred+=bcount.all;				/* Update the current position */
 	pc->current_position+=bcount.all;
 
-	BUG_ON(HWGROUP(drive)->handler);
-	ide_set_handler(drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL);		/* And set the interrupt handler again */
+	ide_set_handler(drive, idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL);		/* And set the interrupt handler again */
 
 	return ide_started;
 }
@@ -1004,7 +999,7 @@
  * It fails at high speeds on the Iomega ZIP drive, so there's a slower version
  * for that drive below. The algorithm is chosen based on drive type
  */
-static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive)
+static ide_startstop_t idefloppy_transfer_pc(struct ata_device *drive, struct request *rq)
 {
 	ide_startstop_t startstop;
 	idefloppy_floppy_t *floppy = drive->driver_data;
@@ -1020,8 +1015,7 @@
 		return ide_stopped;
 	}
 
-	BUG_ON(HWGROUP(drive)->handler);
-	ide_set_handler (drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);	/* Set the interrupt routine */
+	ide_set_handler (drive, idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);	/* Set the interrupt routine */
 	atapi_write(drive, floppy->pc->c, 12); /* Send the actual packet */
 
 	return ide_started;
@@ -1040,7 +1034,7 @@
  * packet, we schedule the packet transfer to occur about 2-3 ticks
  * later in transfer_pc2.
  */
-static int idefloppy_transfer_pc2 (ide_drive_t *drive)
+static int idefloppy_transfer_pc2(struct ata_device *drive, struct request *__rq)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
@@ -1048,7 +1042,7 @@
 	return IDEFLOPPY_WAIT_CMD;		/* Timeout for the packet command */
 }
 
-static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive)
+static ide_startstop_t idefloppy_transfer_pc1(struct ata_device *drive, struct request *__rq)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	ide_startstop_t startstop;
@@ -1070,11 +1064,10 @@
 	 * 25msec is too short, 40 and 50msec work well. idefloppy_pc_intr will
 	 * not be actually used until after the packet is moved in about 50 msec.
 	 */
-	BUG_ON(HWGROUP(drive)->handler);
-	ide_set_handler (drive,
-	  &idefloppy_pc_intr, 		/* service routine for packet command */
+	ide_set_handler(drive,
+	  idefloppy_pc_intr,		/* service routine for packet command */
 	  floppy->ticks,		/* wait this long before "failing" */
-	  &idefloppy_transfer_pc2);	/* fail == transfer_pc2 */
+	  idefloppy_transfer_pc2);	/* fail == transfer_pc2 */
 
 	return ide_started;
 }
@@ -1082,12 +1075,12 @@
 /*
  *	Issue a packet command
  */
-static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc)
+static ide_startstop_t idefloppy_issue_pc(struct ata_device *drive, struct request *rq, idefloppy_pc_t *pc)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	idefloppy_bcount_reg_t bcount;
 	int dma_ok = 0;
-	ide_handler_t *pkt_xfer_routine;
+	ata_handler_t *pkt_xfer_routine;
 
 #if IDEFLOPPY_DEBUG_BUGS
 	if (floppy->pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD && pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
@@ -1113,7 +1106,7 @@
 			pc->error = IDEFLOPPY_ERROR_GENERAL;		/* Giving up */
 		}
 		floppy->failed_pc=NULL;
-		pc->callback(drive);
+		pc->callback(drive, rq);
 		return ide_stopped;
 	}
 #if IDEFLOPPY_DEBUG_LOG
@@ -1127,10 +1120,10 @@
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
-		(void) drive->channel->dmaproc(ide_dma_off, drive);
+		(void) drive->channel->udma(ide_dma_off, drive, NULL);
 	}
 	if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
-		dma_ok=!drive->channel->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
+		dma_ok=!drive->channel->udma(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive, rq);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
 	if (IDE_CONTROL_REG)
@@ -1143,7 +1136,7 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (dma_ok) {							/* Begin DMA, if necessary */
 		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
-		(void) drive->channel->dmaproc(ide_dma_begin, drive);
+		(void) drive->channel->udma(ide_dma_begin, drive, NULL);
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
@@ -1155,23 +1148,22 @@
 	}
 
 	if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) {
-		BUG_ON(HWGROUP(drive)->handler);
-		ide_set_handler (drive, pkt_xfer_routine, IDEFLOPPY_WAIT_CMD, NULL);
+		ide_set_handler(drive, pkt_xfer_routine, 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);
-		return (*pkt_xfer_routine) (drive);
+		return pkt_xfer_routine(drive, rq);
 	}
 }
 
-static void idefloppy_rw_callback (ide_drive_t *drive)
+static void idefloppy_rw_callback(struct ata_device *drive, struct request *rq)
 {
 #if IDEFLOPPY_DEBUG_LOG
 	printk (KERN_INFO "ide-floppy: Reached idefloppy_rw_callback\n");
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
-	idefloppy_end_request(drive, 1);
+	idefloppy_end_request(drive, rq, 1);
 	return;
 }
 
@@ -1266,7 +1258,7 @@
 		2 * test_bit (IDEFLOPPY_USE_READ12, &floppy->flags), block, blocks);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
-	idefloppy_init_pc (pc);
+	idefloppy_init_pc(pc);
 	if (test_bit (IDEFLOPPY_USE_READ12, &floppy->flags)) {
 		pc->c[0] = cmd == READ ? IDEFLOPPY_READ12_CMD : IDEFLOPPY_WRITE12_CMD;
 		put_unaligned (htonl (blocks), (unsigned int *) &pc->c[6]);
@@ -1275,8 +1267,7 @@
 		put_unaligned (htons (blocks), (unsigned short *) &pc->c[7]);
 	}
 	put_unaligned (htonl (block), (unsigned int *) &pc->c[2]);
-	pc->callback = &idefloppy_rw_callback;
-	pc->rq = rq;
+	pc->callback = idefloppy_rw_callback;
 	pc->b_data = rq->buffer;
 	pc->b_count = cmd == READ ? 0 : rq->bio->bi_size;
 	if (rq->flags & REQ_RW)
@@ -1305,13 +1296,13 @@
 				drive->name, floppy->failed_pc->c[0], floppy->sense_key, floppy->asc, floppy->ascq);
 		else
 			printk (KERN_ERR "ide-floppy: %s: I/O error\n", drive->name);
-		idefloppy_end_request(drive, 0);
+		idefloppy_end_request(drive, rq, 0);
 		return ide_stopped;
 	}
 	if (rq->flags & REQ_CMD) {
 		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(drive, 0);
+			idefloppy_end_request(drive, rq, 0);
 			return ide_stopped;
 		}
 		pc = idefloppy_next_pc_storage(drive);
@@ -1320,11 +1311,11 @@
 		pc = (idefloppy_pc_t *) rq->buffer;
 	} else {
 		blk_dump_rq_flags(rq, "ide-floppy: unsupported command in queue");
-		idefloppy_end_request(drive, 0);
+		idefloppy_end_request(drive, rq, 0);
 		return ide_stopped;
 	}
-	pc->rq = rq;
-	return idefloppy_issue_pc (drive, pc);
+
+	return idefloppy_issue_pc(drive, rq, pc);
 }
 
 /*
diff -Nru a/drivers/ide/ide-pci.c b/drivers/ide/ide-pci.c
--- a/drivers/ide/ide-pci.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/ide/ide-pci.c	Tue Apr 30 17:10:25 2002
@@ -201,8 +201,10 @@
 	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_1, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
 	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_9, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
 	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_8, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_9, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
 	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
 	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_11, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_9, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
 	{PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1, pci_init_piix, ata66_piix, ide_init_piix, ide_dmacapable_piix, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
 #endif
 #ifdef CONFIG_BLK_DEV_VIA82CXXX
diff -Nru a/drivers/ide/ide-pmac.c b/drivers/ide/ide-pmac.c
--- a/drivers/ide/ide-pmac.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/ide/ide-pmac.c	Tue Apr 30 17:10:25 2002
@@ -27,6 +27,7 @@
  *    symbols or by storing hooks at arch level).
  *
  */
+
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -77,8 +78,8 @@
 	struct scatterlist*		sg_table;
 	int				sg_nents;
 	int				sg_dma_direction;
-#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
-	
+#endif
+
 } pmac_ide[MAX_HWIFS] __pmacdata;
 
 static int pmac_ide_count;
@@ -255,11 +256,11 @@
 #define IDE_WAKEUP_DELAY_MS	2000
 
 static void pmac_ide_setup_dma(struct device_node *np, int ix);
-static int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive);
-static int pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr);
-static int pmac_ide_tune_chipset(ide_drive_t *drive, byte speed);
-static void pmac_ide_tuneproc(ide_drive_t *drive, byte pio);
-static void pmac_ide_selectproc(ide_drive_t *drive);
+static int pmac_ide_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq);
+static int pmac_ide_build_dmatable(struct ata_device *drive, struct request *rq, int ix, int wr);
+static int pmac_ide_tune_chipset(struct ata_device *drive, byte speed);
+static void pmac_ide_tuneproc(struct ata_device *drive, byte pio);
+static void pmac_ide_selectproc(struct ata_device *drive);
 
 #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
 
@@ -322,7 +323,7 @@
 	ide_hwifs[ix].selectproc = pmac_ide_selectproc;
 	ide_hwifs[ix].speedproc = &pmac_ide_tune_chipset;
 	if (pmac_ide[ix].dma_regs && pmac_ide[ix].dma_table_cpu) {
-		ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc;
+		ide_hwifs[ix].udma = pmac_ide_dmaproc;
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO
 		if (!noautodma)
 			ide_hwifs[ix].autodma = 1;
@@ -405,7 +406,7 @@
 {
 	int result = 1;
 	unsigned long flags;
-	struct ata_channel *hwif = HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	
 	disable_irq(hwif->irq);	/* disable_irq_nosync ?? */
 	udelay(1);
@@ -431,7 +432,7 @@
 	if (result)
 		printk(KERN_ERR "pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n");
 out:
-	SELECT_MASK(HWIF(drive), drive, 0);
+	SELECT_MASK(drive->channel, drive, 0);
 	if (result == 0) {
 		drive->id->dma_ultra &= ~0xFF00;
 		drive->id->dma_mword &= ~0x0F00;
@@ -1024,7 +1025,7 @@
 				    	pmif->dma_table_cpu, pmif->dma_table_dma);
 		return;
 	}
-	ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc;
+	ide_hwifs[ix].udma = pmac_ide_dmaproc;
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO
 	if (!noautodma)
 		ide_hwifs[ix].autodma = 1;
@@ -1092,11 +1093,10 @@
  * for a transfer and sets the DBDMA channel to point to it.
  */
 static int
-pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr)
+pmac_ide_build_dmatable(struct ata_device *drive, struct request *rq, int ix, int wr)
 {
 	struct dbdma_cmd *table;
 	int i, count = 0;
-	struct request *rq = HWGROUP(drive)->rq;
 	volatile struct dbdma_regs *dma = pmac_ide[ix].dma_regs;
 	struct scatterlist *sg;
 
@@ -1166,7 +1166,7 @@
 static void
 pmac_ide_destroy_dmatable (ide_drive_t *drive, int ix)
 {
-	struct pci_dev *dev = HWIF(drive)->pci_dev;
+	struct pci_dev *dev = drive->channel->pci_dev;
 	struct scatterlist *sg = pmac_ide[ix].sg_table;
 	int nents = pmac_ide[ix].sg_nents;
 
@@ -1326,17 +1326,17 @@
 {
 	dma64_addr_t addr = BLK_BOUNCE_HIGH;
 
-	if (on && drive->type == ATA_DISK && HWIF(drive)->highmem) {
+	if (on && drive->type == ATA_DISK && drive->channel->highmem) {
 		if (!PCI_DMA_BUS_IS_PHYS)
 			addr = BLK_BOUNCE_ANY;
 		else
-			addr = HWIF(drive)->pci_dev->dma_mask;
+			addr = drive->channel->pci_dev->dma_mask;
 	}
 
 	blk_queue_bounce_limit(&drive->queue, addr);
 }
 
-int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
+static int pmac_ide_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq)
 {
 	int ix, dstat, reading, ata4;
 	volatile struct dbdma_regs *dma;
@@ -1369,10 +1369,10 @@
 	case ide_dma_write:
 		/* this almost certainly isn't needed since we don't
 		   appear to have a rwproc */
-		if (HWIF(drive)->rwproc)
-			HWIF(drive)->rwproc(drive, func);
+		if (drive->channel->rwproc)
+			drive->channel->rwproc(drive, func);
 		reading = (func == ide_dma_read);
-		if (!pmac_ide_build_dmatable(drive, ix, !reading))
+		if (!pmac_ide_build_dmatable(drive, rq, ix, !reading))
 			return 1;
 		/* Apple adds 60ns to wrDataSetup on reads */
 		if (ata4 && (pmac_ide[ix].timings[unit] & TR_66_UDMA_EN)) {
@@ -1384,11 +1384,10 @@
 		drive->waiting_for_dma = 1;
 		if (drive->type != ATA_DISK)
 			return 0;
-		BUG_ON(HWGROUP(drive)->handler);
-		ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
-		if ((HWGROUP(drive)->rq->flags & REQ_DRIVE_ACB) &&
+		ide_set_handler(drive, ide_dma_intr, WAIT_CMD, NULL);
+		if ((rq->flags & REQ_DRIVE_ACB) &&
 		    (drive->addressing == 1)) {
-			struct ata_taskfile *args = HWGROUP(drive)->rq->special;
+			struct ata_taskfile *args = rq->special;
 			OUT_BYTE(args->taskfile.command, IDE_COMMAND_REG);
 		} else if (drive->addressing) {
 			OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
diff -Nru a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
--- a/drivers/ide/ide-probe.c	Tue Apr 30 17:10:23 2002
+++ b/drivers/ide/ide-probe.c	Tue Apr 30 17:10:23 2002
@@ -438,10 +438,11 @@
  * This routine only knows how to look for drive units 0 and 1
  * on an interface, so any setting of MAX_DRIVES > 2 won't work here.
  */
-static void probe_hwif(struct ata_channel *ch)
+static void channel_probe(struct ata_channel *ch)
 {
 	unsigned int unit;
 	unsigned long flags;
+	int error;
 
 	if (ch->noprobe)
 		return;
@@ -454,96 +455,97 @@
 	/*
 	 * Check for the presence of a channel by probing for drives on it.
 	 */
-
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		struct ata_device *drive = &ch->drives[unit];
 
 		probe_for_drive(drive);
 
-		if (drive->present && !ch->present) {
+		/* drive found, there is a channel it is attached too. */
+		if (drive->present)
 			ch->present = 1;
-		}
 	}
 
-	if (ch->present) {
-		int error = 0;
+	if (!ch->present)
+		goto not_found;
 
-		if (((unsigned long)ch->io_ports[IDE_DATA_OFFSET] | 7) ==
-				((unsigned long)ch->io_ports[IDE_STATUS_OFFSET])) {
-			error += !request_region(ch->io_ports[IDE_DATA_OFFSET], 8, ch->name);
-			ch->straight8 = 1;
-		} else {
-			if (ch->io_ports[IDE_DATA_OFFSET])
-				error += !request_region(ch->io_ports[IDE_DATA_OFFSET], 1, ch->name);
-			if (ch->io_ports[IDE_ERROR_OFFSET])
-				error += !request_region(ch->io_ports[IDE_ERROR_OFFSET], 1, ch->name);
-			if (ch->io_ports[IDE_NSECTOR_OFFSET])
-				error += !request_region(ch->io_ports[IDE_NSECTOR_OFFSET], 1, ch->name);
-			if (ch->io_ports[IDE_SECTOR_OFFSET])
-				error += !request_region(ch->io_ports[IDE_SECTOR_OFFSET], 1, ch->name);
-			if (ch->io_ports[IDE_LCYL_OFFSET])
-				error += !request_region(ch->io_ports[IDE_LCYL_OFFSET], 1, ch->name);
-			if (ch->io_ports[IDE_HCYL_OFFSET])
-				error += !request_region(ch->io_ports[IDE_HCYL_OFFSET], 1, ch->name);
-			if (ch->io_ports[IDE_SELECT_OFFSET])
-				error += !request_region(ch->io_ports[IDE_SELECT_OFFSET], 1, ch->name);
-			if (ch->io_ports[IDE_STATUS_OFFSET])
-				error += !request_region(ch->io_ports[IDE_STATUS_OFFSET], 1, ch->name);
+	error = 0;
 
-		}
-		if (ch->io_ports[IDE_CONTROL_OFFSET])
-			error += !request_region(ch->io_ports[IDE_CONTROL_OFFSET], 1, ch->name);
+	if (((unsigned long)ch->io_ports[IDE_DATA_OFFSET] | 7) ==
+			((unsigned long)ch->io_ports[IDE_STATUS_OFFSET])) {
+		error += !request_region(ch->io_ports[IDE_DATA_OFFSET], 8, ch->name);
+		ch->straight8 = 1;
+	} else {
+		if (ch->io_ports[IDE_DATA_OFFSET])
+			error += !request_region(ch->io_ports[IDE_DATA_OFFSET], 1, ch->name);
+		if (ch->io_ports[IDE_ERROR_OFFSET])
+			error += !request_region(ch->io_ports[IDE_ERROR_OFFSET], 1, ch->name);
+		if (ch->io_ports[IDE_NSECTOR_OFFSET])
+			error += !request_region(ch->io_ports[IDE_NSECTOR_OFFSET], 1, ch->name);
+		if (ch->io_ports[IDE_SECTOR_OFFSET])
+			error += !request_region(ch->io_ports[IDE_SECTOR_OFFSET], 1, ch->name);
+		if (ch->io_ports[IDE_LCYL_OFFSET])
+			error += !request_region(ch->io_ports[IDE_LCYL_OFFSET], 1, ch->name);
+		if (ch->io_ports[IDE_HCYL_OFFSET])
+			error += !request_region(ch->io_ports[IDE_HCYL_OFFSET], 1, ch->name);
+		if (ch->io_ports[IDE_SELECT_OFFSET])
+			error += !request_region(ch->io_ports[IDE_SELECT_OFFSET], 1, ch->name);
+		if (ch->io_ports[IDE_STATUS_OFFSET])
+			error += !request_region(ch->io_ports[IDE_STATUS_OFFSET], 1, ch->name);
+
+	}
+	if (ch->io_ports[IDE_CONTROL_OFFSET])
+		error += !request_region(ch->io_ports[IDE_CONTROL_OFFSET], 1, ch->name);
 #if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
-		if (ch->io_ports[IDE_IRQ_OFFSET])
-			error += !request_region(ch->io_ports[IDE_IRQ_OFFSET], 1, ch->name);
+	if (ch->io_ports[IDE_IRQ_OFFSET])
+		error += !request_region(ch->io_ports[IDE_IRQ_OFFSET], 1, ch->name);
 #endif
 
-		/* Some neccessary register area was already used. Skip this
-		 * device.
-		 */
-		if (
+	/* Some neccessary register area was already used. Skip this device.
+	 */
+
+	if (
 #if CONFIG_BLK_DEV_PDC4030
-				(ch->chipset != ide_pdc4030 || ch->unit == 0) &&
+			(ch->chipset != ide_pdc4030 || ch->unit == 0) &&
 #endif
-				error) {
-			/* FIXME: We should be dealing properly with partial IO
-			 * region allocations here.
-			 */
-			ch->present = 0;
-			printk("%s: error: ports already in use!\n", ch->name);
+			error) {
 
-		}
+		/* FIXME: We should be dealing properly with partial IO region
+		 * allocations here.
+		 */
+
+		ch->present = 0;
+		printk("%s: error: ports already in use!\n", ch->name);
 	}
 
-	if (ch->present) {
-		/* Register this hardware interface within the global device tree.
-		 */
-		sprintf(ch->dev.bus_id, "%04x", ch->io_ports[IDE_DATA_OFFSET]);
-		sprintf(ch->dev.name, "ide");
-		ch->dev.driver_data = ch;
+	if (!ch->present)
+		goto not_found;
+
+	/* Register this hardware interface within the global device tree.
+	 */
+	sprintf(ch->dev.bus_id, "%04x", ch->io_ports[IDE_DATA_OFFSET]);
+	sprintf(ch->dev.name, "ide");
+	ch->dev.driver_data = ch;
 #ifdef CONFIG_BLK_DEV_IDEPCI
-		if (ch->pci_dev)
-			ch->dev.parent = &ch->pci_dev->dev;
-		else
+	if (ch->pci_dev)
+		ch->dev.parent = &ch->pci_dev->dev;
+	else
 #endif
-			ch->dev.parent = NULL; /* Would like to do = &device_legacy */
+		ch->dev.parent = NULL; /* Would like to do = &device_legacy */
 
-		device_register(&ch->dev);
+	device_register(&ch->dev);
 
-		if (ch->io_ports[IDE_CONTROL_OFFSET] && ch->reset) {
-			unsigned long timeout = jiffies + WAIT_WORSTCASE;
-			byte stat;
-
-			printk("%s: reset\n", ch->name);
-			OUT_BYTE(12, ch->io_ports[IDE_CONTROL_OFFSET]);
-			udelay(10);
-			OUT_BYTE(8, ch->io_ports[IDE_CONTROL_OFFSET]);
-			do {
-				ide_delay_50ms();
-				stat = IN_BYTE(ch->io_ports[IDE_STATUS_OFFSET]);
-			} while ((stat & BUSY_STAT) && 0 < (signed long)(timeout - jiffies));
-
-		}
+	if (ch->io_ports[IDE_CONTROL_OFFSET] && ch->reset) {
+		unsigned long timeout = jiffies + WAIT_WORSTCASE;
+		byte stat;
+
+		printk("%s: reset\n", ch->name);
+		OUT_BYTE(12, ch->io_ports[IDE_CONTROL_OFFSET]);
+		udelay(10);
+		OUT_BYTE(8, ch->io_ports[IDE_CONTROL_OFFSET]);
+		do {
+			ide_delay_50ms();
+			stat = IN_BYTE(ch->io_ports[IDE_STATUS_OFFSET]);
+		} while ((stat & BUSY_STAT) && 0 < (signed long)(timeout - jiffies));
 	}
 
 	__restore_flags(flags);	/* local CPU only */
@@ -551,16 +553,19 @@
 	/*
 	 * Now setup the PIO transfer modes of the drives on this channel.
 	 */
-	if (ch->present) {
-		for (unit = 0; unit < MAX_DRIVES; ++unit) {
-			struct ata_device *drive = &ch->drives[unit];
-
-			if (drive->present && (drive->autotune == 1)) {
-				if (drive->channel->tuneproc)
-					drive->channel->tuneproc(drive, 255);	/* auto-tune PIO mode */
-			}
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		struct ata_device *drive = &ch->drives[unit];
+
+		if (drive->present && (drive->autotune == 1)) {
+			if (drive->channel->tuneproc)
+				drive->channel->tuneproc(drive, 255);	/* auto-tune PIO mode */
 		}
 	}
+
+	return;
+
+not_found:
+	__restore_flags(flags);
 }
 
 /*
@@ -682,12 +687,7 @@
 			spin_unlock_irqrestore(&ide_lock, flags);
 			return 1;
 		}
-		memset(hwgroup, 0, sizeof(ide_hwgroup_t));
-		hwgroup->rq       = NULL;
-		hwgroup->handler  = NULL;
-		hwgroup->drive    = NULL;
-		hwgroup->flags	  = 0;
-
+		memset(hwgroup, 0, sizeof(*hwgroup));
 		init_timer(&hwgroup->timer);
 		hwgroup->timer.function = &ide_timer_expiry;
 		hwgroup->timer.data = (unsigned long) hwgroup;
@@ -716,21 +716,17 @@
 	}
 
 	/*
-	 * Everything is okay.
+	 * Everything is okay. Tag us as member of this hardware group.
 	 */
 	ch->hwgroup = hwgroup;
-
 	for (i = 0; i < MAX_DRIVES; ++i) {
 		struct ata_device *drive = &ch->drives[i];
 
 		if (!drive->present)
 			continue;
 
-		if (!hwgroup->drive)
-			hwgroup->drive = drive;
-
-		drive->next = hwgroup->drive->next;
-		hwgroup->drive->next = drive;
+		if (!hwgroup->XXX_drive)
+			hwgroup->XXX_drive = drive;
 
 		init_device_queue(drive);
 	}
@@ -833,58 +829,79 @@
 	return;
 }
 
-static int hwif_init(struct ata_channel *hwif)
+/*
+ * Returns the queue which corresponds to a given device.
+ *
+ * FIXME: this should take struct block_device * as argument in future.
+ */
+
+static request_queue_t *ata_get_queue(kdev_t dev)
 {
-	if (!hwif->present)
-		return 0;
-	if (!hwif->irq) {
-		if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET])))
-		{
-			printk("%s: DISABLED, NO IRQ\n", hwif->name);
-			return (hwif->present = 0);
+	struct ata_channel *ch = (struct ata_channel *)blk_dev[major(dev)].data;
+
+	/* FIXME: ALLERT: This discriminates between master and slave! */
+	return &ch->drives[DEVICE_NR(dev) & 1].queue;
+}
+
+static void channel_init(struct ata_channel *ch)
+{
+	if (!ch->present)
+		return;
+
+	/* we set it back to 1 if all is ok below */
+	ch->present = 0;
+
+	if (!ch->irq) {
+		if (!(ch->irq = ide_default_irq(ch->io_ports[IDE_DATA_OFFSET]))) {
+			printk("%s: DISABLED, NO IRQ\n", ch->name);
+
+			return;
 		}
 	}
 #ifdef CONFIG_BLK_DEV_HD
-	if (hwif->irq == HD_IRQ && hwif->io_ports[IDE_DATA_OFFSET] != HD_DATA) {
-		printk("%s: CANNOT SHARE IRQ WITH OLD HARDDISK DRIVER (hd.c)\n", hwif->name);
-		return (hwif->present = 0);
+	if (ch->irq == HD_IRQ && ch->io_ports[IDE_DATA_OFFSET] != HD_DATA) {
+		printk("%s: CANNOT SHARE IRQ WITH OLD HARDDISK DRIVER (hd.c)\n", ch->name);
+
+		return;
 	}
 #endif
 
-	hwif->present = 0; /* we set it back to 1 if all is ok below */
+	if (devfs_register_blkdev (ch->major, ch->name, ide_fops)) {
+		printk("%s: UNABLE TO GET MAJOR NUMBER %d\n", ch->name, ch->major);
 
-	if (devfs_register_blkdev (hwif->major, hwif->name, ide_fops)) {
-		printk("%s: UNABLE TO GET MAJOR NUMBER %d\n", hwif->name, hwif->major);
-		return (hwif->present = 0);
+		return;
 	}
 
-	if (init_irq(hwif)) {
-		int i = hwif->irq;
+	if (init_irq(ch)) {
+		int irq = ch->irq;
 		/*
-		 *	It failed to initialise. Find the default IRQ for 
-		 *	this port and try that.
+		 * It failed to initialise. Find the default IRQ for
+		 * this port and try that.
 		 */
-		if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) {
-			printk("%s: Disabled unable to get IRQ %d.\n", hwif->name, i);
-			(void) unregister_blkdev (hwif->major, hwif->name);
-			return (hwif->present = 0);
+		if (!(ch->irq = ide_default_irq(ch->io_ports[IDE_DATA_OFFSET]))) {
+			printk(KERN_INFO "%s: disabled; unable to get IRQ %d.\n", ch->name, irq);
+			(void) unregister_blkdev (ch->major, ch->name);
+
+			return;
 		}
-		if (init_irq(hwif)) {
-			printk("%s: probed IRQ %d and default IRQ %d failed.\n",
-				hwif->name, i, hwif->irq);
-			(void) unregister_blkdev (hwif->major, hwif->name);
-			return (hwif->present = 0);
+		if (init_irq(ch)) {
+			printk(KERN_INFO "%s: probed IRQ %d and default IRQ %d failed.\n",
+				ch->name, irq, ch->irq);
+			(void) unregister_blkdev(ch->major, ch->name);
+
+			return;
 		}
-		printk("%s: probed IRQ %d failed, using default.\n",
-			hwif->name, hwif->irq);
+		printk(KERN_INFO "%s: probed IRQ %d failed, using default.\n", ch->name, ch->irq);
 	}
 
-	init_gendisk(hwif);
-	blk_dev[hwif->major].data = hwif;
-	blk_dev[hwif->major].queue = ide_get_queue;
-	hwif->present = 1;	/* success */
+	init_gendisk(ch);
+	blk_dev[ch->major].data = ch;
+	blk_dev[ch->major].queue = ata_get_queue;
+
+	/* all went well, flag this channel entry as valid */
+	ch->present = 1;
 
-	return hwif->present;
+	return;
 }
 
 int ideprobe_init (void)
@@ -901,9 +918,9 @@
 	 */
 	for (index = 0; index < MAX_HWIFS; ++index)
 		if (probe[index])
-			probe_hwif(&ide_hwifs[index]);
+			channel_probe(&ide_hwifs[index]);
 	for (index = 0; index < MAX_HWIFS; ++index)
 		if (probe[index])
-			hwif_init(&ide_hwifs[index]);
+			channel_init(&ide_hwifs[index]);
 	return 0;
 }
diff -Nru a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
--- a/drivers/ide/ide-tape.c	Tue Apr 30 17:10:24 2002
+++ b/drivers/ide/ide-tape.c	Tue Apr 30 17:10:24 2002
@@ -726,7 +726,8 @@
 	int b_count;
 	byte *buffer;				/* Data buffer */
 	byte *current_position;			/* Pointer into the above buffer */
-	ide_startstop_t (*callback) (ide_drive_t *);	/* Called when this packet command is completed */
+	/* Called when this packet command is completed */
+	ide_startstop_t (*callback) (struct ata_device *, struct request *);
 	byte pc_buffer[IDETAPE_PC_BUFFER_SIZE];	/* Temporary buffer */
 	unsigned long flags;			/* Status/Action bit flags: long for set_bit */
 } idetape_pc_t;
@@ -1835,9 +1836,8 @@
  *	idetape_end_request is used to finish servicing a request, and to
  *	insert a pending pipeline request into the main device queue.
  */
-static int idetape_end_request(ide_drive_t *drive, int uptodate)
+static int idetape_end_request(struct ata_device *drive, struct request *rq, int uptodate)
 {
-	struct request *rq = HWGROUP(drive)->rq;
 	idetape_tape_t *tape = drive->driver_data;
 	unsigned long flags;
 	int error;
@@ -1935,7 +1935,7 @@
 	return 0;
 }
 
-static ide_startstop_t idetape_request_sense_callback (ide_drive_t *drive)
+static ide_startstop_t idetape_request_sense_callback(struct ata_device *drive, struct request *rq)
 {
 	idetape_tape_t *tape = drive->driver_data;
 
@@ -1945,17 +1945,17 @@
 #endif /* IDETAPE_DEBUG_LOG */
 	if (!tape->pc->error) {
 		idetape_analyze_error (drive, (idetape_request_sense_result_t *) tape->pc->buffer);
-		idetape_end_request(drive, 1);
+		idetape_end_request(drive, rq, 1);
 	} else {
 		printk (KERN_ERR "ide-tape: Error in REQUEST SENSE itself - Aborting request!\n");
-		idetape_end_request(drive, 0);
+		idetape_end_request(drive, rq, 0);
 	}
 	return ide_stopped;
 }
 
 static void idetape_create_request_sense_cmd (idetape_pc_t *pc)
 {
-	idetape_init_pc (pc);	
+	idetape_init_pc (pc);
 	pc->c[0] = IDETAPE_REQUEST_SENSE_CMD;
 	pc->c[4] = 20;
 	pc->request_transfer = 18;
@@ -2015,7 +2015,7 @@
  *	ide.c will be able to service requests from another device on
  *	the same interface while we are polling for DSC.
  */
-static void idetape_postpone_request (ide_drive_t *drive)
+static void idetape_postpone_request(struct ata_device *drive, struct request *rq)
 {
 	idetape_tape_t *tape = drive->driver_data;
 
@@ -2023,7 +2023,7 @@
 	if (tape->debug_level >= 4)
 		printk(KERN_INFO "ide-tape: idetape_postpone_request\n");
 #endif
-	tape->postponed_rq = HWGROUP(drive)->rq;
+	tape->postponed_rq = rq;
 	ide_stall_queue(drive, tape->dsc_polling_frequency);
 }
 
@@ -2035,7 +2035,7 @@
  *	algorithm described before idetape_issue_packet_command.
  *
  */
-static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
+static ide_startstop_t idetape_pc_intr(struct ata_device *drive, struct request *rq)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_status_reg_t status;
@@ -2058,7 +2058,7 @@
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
-		if (drive->channel->dmaproc(ide_dma_end, drive)) {
+		if (drive->channel->udma(ide_dma_end, drive, NULL)) {
 			/*
 			 * A DMA error is sometimes expected. For example,
 			 * if the tape is crossing a filemark during a
@@ -2121,18 +2121,18 @@
 			tape->dsc_polling_start = jiffies;
 			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 */
+			idetape_postpone_request(drive, rq);		/* Allow ide.c to handle other requests */
 			return ide_stopped;
 		}
 		if (tape->failed_pc == pc)
 			tape->failed_pc = NULL;
-		return pc->callback(drive);			/* Command finished - Call the callback function */
+		return pc->callback(drive, rq);			/* 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");
-		drive->channel->dmaproc(ide_dma_off, drive);
+		drive->channel->udma(ide_dma_off, drive, NULL);
 		return ide_stopped;
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
@@ -2155,8 +2155,7 @@
 			if (temp > pc->buffer_size) {
 				printk (KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n");
 				idetape_discard_data (drive, bcount.all);
-				BUG_ON(HWGROUP(drive)->handler);
-				ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
+				ide_set_handler(drive, idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
 				return ide_started;
 			}
 #if IDETAPE_DEBUG_LOG
@@ -2182,8 +2181,7 @@
 	if (tape->debug_level >= 2)
 		printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes on that interrupt\n", pc->c[0], bcount.all);
 #endif
-	BUG_ON(HWGROUP(drive)->handler);
-	ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);	/* And set the interrupt handler again */
+	ide_set_handler(drive, idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);	/* And set the interrupt handler again */
 	return ide_started;
 }
 
@@ -2229,7 +2227,7 @@
  *		we will handle the next request.
  *
  */
-static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive)
+static ide_startstop_t idetape_transfer_pc(struct ata_device *drive, struct request *__rq)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc = tape->pc;
@@ -2257,13 +2255,12 @@
 		return ide_stopped;
 	}
 	tape->cmd_start_time = jiffies;
-	BUG_ON(HWGROUP(drive)->handler);
-	ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);	/* Set the interrupt routine */
+	ide_set_handler(drive, idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);	/* Set the interrupt routine */
 	atapi_write(drive,pc->c,12);	/* Send the actual packet */
 	return ide_started;
 }
 
-static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc)
+static ide_startstop_t idetape_issue_packet_command(struct ata_device *drive, struct request *rq, idetape_pc_t *pc)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_bcount_reg_t bcount;
@@ -2297,7 +2294,7 @@
 			pc->error = IDETAPE_ERROR_GENERAL;		/* Giving up */
 		}
 		tape->failed_pc = NULL;
-		return pc->callback(drive);
+		return pc->callback(drive, rq);
 	}
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 2)
@@ -2312,10 +2309,10 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
 		printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n");
-		(void) drive->channel->dmaproc(ide_dma_off, drive);
+		(void) drive->channel->udma(ide_dma_off, drive, NULL);
 	}
 	if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
-		dma_ok = !drive->channel->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
+		dma_ok = !drive->channel->udma(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive, rq);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
 	if (IDE_CONTROL_REG)
@@ -2327,24 +2324,23 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (dma_ok) {						/* Begin DMA, if necessary */
 		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
-		(void) drive->channel->dmaproc(ide_dma_begin, drive);
+		(void) drive->channel->udma(ide_dma_begin, drive, NULL);
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 	if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
-		BUG_ON(HWGROUP(drive)->handler);
-		ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL);
+		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);
-		return idetape_transfer_pc(drive);
+		return idetape_transfer_pc(drive, rq);
 	}
 }
 
 /*
  *	General packet command callback function.
  */
-static ide_startstop_t idetape_pc_callback (ide_drive_t *drive)
+static ide_startstop_t idetape_pc_callback(struct ata_device *drive, struct request *rq)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	
@@ -2353,7 +2349,7 @@
 		printk (KERN_INFO "ide-tape: Reached idetape_pc_callback\n");
 #endif /* IDETAPE_DEBUG_LOG */
 
-	idetape_end_request(drive, tape->pc->error ? 0 : 1);
+	idetape_end_request(drive, rq, tape->pc->error ? 0 : 1);
 	return ide_stopped;
 }
 
@@ -2375,10 +2371,10 @@
 		pc->request_transfer = 24;
 	else
 		pc->request_transfer = 50;
-	pc->callback = &idetape_pc_callback;
+	pc->callback = idetape_pc_callback;
 }
 
-static ide_startstop_t idetape_onstream_buffer_fill_callback (ide_drive_t *drive)
+static ide_startstop_t idetape_onstream_buffer_fill_callback (struct ata_device *drive, struct request *rq)
 {
 	idetape_tape_t *tape = drive->driver_data;
 
@@ -2402,7 +2398,7 @@
 	if (tape->debug_level >= 1)
 		printk(KERN_INFO "ide-tape: buffer fill callback, %d/%d\n", tape->cur_frames, tape->max_frames);
 #endif
-	idetape_end_request(drive, tape->pc->error ? 0 : 1);
+	idetape_end_request(drive, rq, tape->pc->error ? 0 : 1);
 	return ide_stopped;
 }
 
@@ -2466,7 +2462,7 @@
 	tape->max_insert_speed = max(tape->max_insert_speed, 500);
 }
 
-static ide_startstop_t idetape_media_access_finished (ide_drive_t *drive)
+static ide_startstop_t idetape_media_access_finished(struct ata_device *drive, struct request *rq)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc = tape->pc;
@@ -2487,13 +2483,12 @@
 		pc->error = IDETAPE_ERROR_GENERAL;
 		tape->failed_pc = NULL;
 	}
-	return pc->callback (drive);
+	return pc->callback(drive, rq);
 }
 
-static ide_startstop_t idetape_rw_callback (ide_drive_t *drive)
+static ide_startstop_t idetape_rw_callback(struct ata_device *drive, struct request *rq)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	struct request *rq = HWGROUP(drive)->rq;
 	int blocks = tape->pc->actually_transferred / tape->tape_block_size;
 
 	tape->avg_size += blocks * tape->tape_block_size;
@@ -2522,9 +2517,9 @@
 	rq->current_nr_sectors -= blocks;
 
 	if (!tape->pc->error)
-		idetape_end_request(drive, 1);
+		idetape_end_request(drive, rq, 1);
 	else
-		idetape_end_request(drive, tape->pc->error);
+		idetape_end_request(drive, rq, tape->pc->error);
 	return ide_stopped;
 }
 
@@ -2536,7 +2531,7 @@
 	pc->c[0] = IDETAPE_READ_CMD;
 	put_unaligned (htonl (length), (unsigned int *) &pc->c[1]);
 	pc->c[1] = 1;
-	pc->callback = &idetape_rw_callback;
+	pc->callback = idetape_rw_callback;
 	pc->bio = bio;
 	bv->bv_len = 0;
 	pc->buffer = NULL;
@@ -2569,7 +2564,7 @@
 	pc->c[1] = IDETAPE_RETRIEVE_FAULTY_BLOCK;
 	pc->c[7] = size >> 8;
 	pc->c[8] = size & 0xff;
-	pc->callback = &idetape_pc_callback;
+	pc->callback = idetape_pc_callback;
 	pc->bio = bio;
 	atomic_set(&bio->bi_cnt, 0);
 	pc->buffer = NULL;
@@ -2588,7 +2583,7 @@
 	pc->c[0] = IDETAPE_WRITE_CMD;
 	put_unaligned (htonl (length), (unsigned int *) &pc->c[1]);
 	pc->c[1] = 1;
-	pc->callback = &idetape_rw_callback;
+	pc->callback = idetape_rw_callback;
 	set_bit (PC_WRITING, &pc->flags);
 	if (tape->onstream) {
 		while (p) {
@@ -2635,7 +2630,7 @@
 		 *	We do not support buffer cache originated requests.
 		 */
 		printk (KERN_NOTICE "ide-tape: %s: Unsupported command in request queue (%ld)\n", drive->name, rq->flags);
-		ide_end_request(drive, 0);			/* Let the common code handle it */
+		ide_end_request(drive, rq, 0);			/* Let the common code handle it */
 		return ide_stopped;
 	}
 
@@ -2643,13 +2638,13 @@
 	 *	Retry a failed packet command
 	 */
 	if (tape->failed_pc != NULL && tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
-		return idetape_issue_packet_command (drive, tape->failed_pc);
+		return idetape_issue_packet_command(drive, rq, 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(drive, 0);
+			idetape_end_request(drive, rq, 0);
 			return ide_stopped;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
@@ -2726,14 +2721,14 @@
 		} else if ((signed long) (jiffies - tape->dsc_timeout) > 0) {
 			printk (KERN_ERR "ide-tape: %s: DSC timeout\n", tape->name);
 			if (rq->flags == IDETAPE_PC_RQ2) {
-				idetape_media_access_finished (drive);
+				idetape_media_access_finished(drive, rq);
 				return ide_stopped;
 			} else {
 				return ide_stopped;
 			}
 		} else if (jiffies - tape->dsc_polling_start > IDETAPE_DSC_MA_THRESHOLD)
 			tape->dsc_polling_frequency = IDETAPE_DSC_MA_SLOW;
-		idetape_postpone_request (drive);
+		idetape_postpone_request(drive, rq);
 		return ide_stopped;
 	}
 	switch (rq->flags) {
@@ -2777,7 +2772,7 @@
 			break;
 		case IDETAPE_ABORTED_WRITE_RQ:
 			rq->flags = IDETAPE_WRITE_RQ;
-			idetape_end_request(drive, IDETAPE_ERROR_EOD);
+			idetape_end_request(drive, rq, IDETAPE_ERROR_EOD);
 			return ide_stopped;
 		case IDETAPE_ABORTED_READ_RQ:
 #if IDETAPE_DEBUG_LOG
@@ -2785,21 +2780,21 @@
 				printk(KERN_INFO "ide-tape: %s: detected aborted read rq\n", tape->name);
 #endif
 			rq->flags = IDETAPE_READ_RQ;
-			idetape_end_request(drive, IDETAPE_ERROR_EOD);
+			idetape_end_request(drive, rq, IDETAPE_ERROR_EOD);
 			return ide_stopped;
 		case IDETAPE_PC_RQ1:
 			pc = (idetape_pc_t *) rq->buffer;
 			rq->flags = IDETAPE_PC_RQ2;
 			break;
 		case IDETAPE_PC_RQ2:
-			idetape_media_access_finished (drive);
+			idetape_media_access_finished(drive, rq);
 			return ide_stopped;
 		default:
 			printk (KERN_ERR "ide-tape: bug in IDETAPE_RQ_CMD macro\n");
-			idetape_end_request(drive, 0);
+			idetape_end_request(drive, rq, 0);
 			return ide_stopped;
 	}
-	return idetape_issue_packet_command (drive, pc);
+	return idetape_issue_packet_command(drive, rq, pc);
 }
 
 /*
@@ -3102,7 +3097,7 @@
 	spin_lock_irq(&tape->spinlock);
 }
 
-static ide_startstop_t idetape_read_position_callback (ide_drive_t *drive)
+static ide_startstop_t idetape_read_position_callback(struct ata_device *drive, struct request *rq)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_read_position_result_t *result;
@@ -3123,7 +3118,7 @@
 		if (result->bpu) {
 			printk (KERN_INFO "ide-tape: Block location is unknown to the tape\n");
 			clear_bit (IDETAPE_ADDRESS_VALID, &tape->flags);
-			idetape_end_request(drive, 0);
+			idetape_end_request(drive, rq, 0);
 		} else {
 #if IDETAPE_DEBUG_LOG
 			if (tape->debug_level >= 2)
@@ -3134,10 +3129,10 @@
 			tape->last_frame_position = ntohl (result->last_block);
 			tape->blocks_in_buffer = result->blocks_in_buffer[2];
 			set_bit (IDETAPE_ADDRESS_VALID, &tape->flags);
-			idetape_end_request(drive, 1);
+			idetape_end_request(drive, rq, 1);
 		}
 	} else {
-		idetape_end_request(drive, 0);
+		idetape_end_request(drive, rq, 0);
 	}
 	return ide_stopped;
 }
@@ -3160,14 +3155,14 @@
 		pc->c[1] = 1; /* Immed bit */
 	pc->c[4] = write_filemark;  /* not used for OnStream ?? */
 	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
-	pc->callback = &idetape_pc_callback;
+	pc->callback = idetape_pc_callback;
 }
 
 static void idetape_create_test_unit_ready_cmd(idetape_pc_t *pc)
 {
 	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_TEST_UNIT_READY_CMD;
-	pc->callback = &idetape_pc_callback;
+	pc->callback = idetape_pc_callback;
 }
 
 /*
@@ -3213,7 +3208,7 @@
 			pc->c[4] = 4;
 	}
 	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
-	pc->callback = &idetape_pc_callback;
+	pc->callback = idetape_pc_callback;
 }
 
 static int idetape_wait_ready (ide_drive_t *drive, unsigned long long timeout)
@@ -3275,7 +3270,7 @@
 	idetape_init_pc (pc);
 	pc->c[0] = IDETAPE_READ_POSITION_CMD;
 	pc->request_transfer = 20;
-	pc->callback = &idetape_read_position_callback;
+	pc->callback = idetape_read_position_callback;
 }
 
 static int idetape_read_position (ide_drive_t *drive)
@@ -3331,7 +3326,7 @@
                  */
 		pc->c[9] = skip << 7;
 	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
-	pc->callback = &idetape_pc_callback;
+	pc->callback = idetape_pc_callback;
 }
 
 static int idetape_create_prevent_cmd (ide_drive_t *drive, idetape_pc_t *pc, int prevent)
@@ -3344,7 +3339,7 @@
 	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_PREVENT_CMD;
 	pc->c[4] = prevent;
-	pc->callback = &idetape_pc_callback;
+	pc->callback = idetape_pc_callback;
 	return 1;
 }
 
@@ -3603,7 +3598,7 @@
 	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_INQUIRY_CMD;
 	pc->c[4] = pc->request_transfer = 254;
-	pc->callback = &idetape_pc_callback;
+	pc->callback = idetape_pc_callback;
 }
 
 static void idetape_create_rewind_cmd (ide_drive_t *drive, idetape_pc_t *pc)
@@ -3615,7 +3610,7 @@
 	if (tape->onstream)
 		pc->c[1] = 1;
 	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
-	pc->callback = &idetape_pc_callback;
+	pc->callback = idetape_pc_callback;
 }
 
 static void idetape_create_mode_select_cmd (idetape_pc_t *pc, int length)
@@ -3626,7 +3621,7 @@
 	pc->c[1] = 0x10;
 	put_unaligned (htons(length), (unsigned short *) &pc->c[3]);
 	pc->request_transfer = 255;
-	pc->callback = &idetape_pc_callback;
+	pc->callback = idetape_pc_callback;
 }
 
 static void idetape_create_erase_cmd (idetape_pc_t *pc)
@@ -3635,7 +3630,7 @@
 	pc->c[0] = IDETAPE_ERASE_CMD;
 	pc->c[1] = 1;
 	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
-	pc->callback = &idetape_pc_callback;
+	pc->callback = idetape_pc_callback;
 }
 
 static void idetape_create_space_cmd (idetape_pc_t *pc,int count,byte cmd)
diff -Nru a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
--- a/drivers/ide/ide-taskfile.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/ide/ide-taskfile.c	Tue Apr 30 17:10:25 2002
@@ -260,7 +260,7 @@
 {
 	byte stat = 0;
 	if (drive->waiting_for_dma)
-		return drive->channel->dmaproc(ide_dma_test_irq, drive);
+		return drive->channel->udma(ide_dma_test_irq, drive, NULL);
 #if 0
 	/* need to guarantee 400ns since last command was issued */
 	udelay(1);
@@ -294,7 +294,6 @@
 {
 	int i;
 
-
 	if (drive_is_ready(drive))
 		return;
 
@@ -306,30 +305,24 @@
 	}
 }
 
-static ide_startstop_t pre_task_mulout_intr(ide_drive_t *drive, struct request *rq)
+static ide_startstop_t pre_task_mulout_intr(struct ata_device *drive, struct request *rq)
 {
 	struct ata_taskfile *args = rq->special;
 	ide_startstop_t startstop;
 
-	/*
-	 * assign private copy for multi-write
-	 */
-	memcpy(&HWGROUP(drive)->wrq, rq, sizeof(struct request));
-
 	if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ))
 		return startstop;
 
 	ata_poll_drive_ready(drive);
 
-	return args->handler(drive);
+	return args->handler(drive, rq);
 }
 
-static ide_startstop_t task_mulout_intr (ide_drive_t *drive)
+static ide_startstop_t task_mulout_intr(struct ata_device *drive, struct request *rq)
 {
-	byte stat		= GET_STAT();
-	struct request *rq	= &HWGROUP(drive)->wrq;
-	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
-	int mcount		= drive->mult_count;
+	u8 stat = GET_STAT();
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	int mcount = drive->mult_count;
 	ide_startstop_t startstop;
 
 	/*
@@ -339,11 +332,11 @@
 	if (!rq->nr_sectors) {
 		if (stat & (ERR_STAT|DRQ_STAT)) {
 			startstop = ide_error(drive, "task_mulout_intr", stat);
-			memcpy(rq, HWGROUP(drive)->rq, sizeof(struct request));
+
 			return startstop;
 		}
 
-		__ide_end_request(drive, 1, rq->hard_nr_sectors);
+		__ide_end_request(drive, rq, 1, rq->hard_nr_sectors);
 		rq->bio = NULL;
 
 		return ide_stopped;
@@ -352,7 +345,7 @@
 	if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
 		if (stat & (ERR_STAT | DRQ_STAT)) {
 			startstop = ide_error(drive, "task_mulout_intr", stat);
-			memcpy(rq, HWGROUP(drive)->rq, sizeof(struct request));
+
 			return startstop;
 		}
 
@@ -425,7 +418,7 @@
 	else
 		printk("   rq->                   = null\n");
 #endif
- 
+
 	/* (ks/hs): Moved to start, do not use for multiple out commands */
 	if (args->handler != task_mulout_intr) {
 		if (IDE_CONTROL_REG)
@@ -465,9 +458,9 @@
 	} else {
 		/* for dma commands we down set the handler */
 		if (drive->using_dma &&
-		!(drive->channel->dmaproc(((args->taskfile.command == WIN_WRITEDMA)
+		!(drive->channel->udma(((args->taskfile.command == WIN_WRITEDMA)
 					|| (args->taskfile.command == WIN_WRITEDMA_EXT))
-					? ide_dma_write : ide_dma_read, drive)));
+					? ide_dma_write : ide_dma_read, drive, rq)));
 	}
 
 	return ide_started;
@@ -476,11 +469,11 @@
 /*
  * This is invoked on completion of a WIN_SETMULT cmd.
  */
-ide_startstop_t set_multmode_intr(struct ata_device *drive)
+ide_startstop_t set_multmode_intr(struct ata_device *drive, struct request *__rq)
 {
 	u8 stat;
 
-	if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT)) {
+	if (OK_STAT(stat = GET_STAT(),READY_STAT,BAD_STAT)) {
 		drive->mult_count = drive->mult_req;
 	} else {
 		drive->mult_req = drive->mult_count = 0;
@@ -493,9 +486,9 @@
 /*
  * This is invoked on completion of a WIN_SPECIFY cmd.
  */
-ide_startstop_t set_geometry_intr (ide_drive_t *drive)
+ide_startstop_t set_geometry_intr(struct ata_device *drive, struct request *__rq)
 {
-	byte stat;
+	u8 stat;
 
 	if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT))
 		return ide_stopped;
@@ -503,18 +496,18 @@
 	if (stat & (ERR_STAT|DRQ_STAT))
 		return ide_error(drive, "set_geometry_intr", stat);
 
-	ide_set_handler(drive, &set_geometry_intr, WAIT_CMD, NULL);
+	ide_set_handler(drive, set_geometry_intr, WAIT_CMD, NULL);
 	return ide_started;
 }
 
 /*
  * This is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
  */
-ide_startstop_t recal_intr(ide_drive_t *drive)
+ide_startstop_t recal_intr(struct ata_device *drive, struct request *__rq)
 {
-	byte stat = GET_STAT();
+	u8 stat;
 
-	if (!OK_STAT(stat,READY_STAT,BAD_STAT))
+	if (!OK_STAT(stat = GET_STAT(),READY_STAT,BAD_STAT))
 		return ide_error(drive, "recal_intr", stat);
 	return ide_stopped;
 }
@@ -522,16 +515,19 @@
 /*
  * Handler for commands without a data phase
  */
-ide_startstop_t task_no_data_intr (ide_drive_t *drive)
+ide_startstop_t task_no_data_intr(struct ata_device *drive, struct request *rq)
 {
-	struct ata_taskfile *args = HWGROUP(drive)->rq->special;
-	byte stat		= GET_STAT();
+	u8 stat;
+	struct ata_taskfile *args = rq->special;
 
 	ide__sti();	/* local CPU only */
 
-	if (!OK_STAT(stat, READY_STAT, BAD_STAT))
-		return ide_error(drive, "task_no_data_intr", stat);
-		/* calls ide_end_drive_cmd */
+	if (!OK_STAT(stat = GET_STAT(), READY_STAT, BAD_STAT)) {
+		/* Keep quite for NOP becouse they are expected to fail. */
+		if (args && args->taskfile.command != WIN_NOP)
+			return ide_error(drive, "task_no_data_intr", stat);
+	}
+
 	if (args)
 		ide_end_drive_cmd (drive, stat, GET_ERR());
 
@@ -541,11 +537,10 @@
 /*
  * Handler for command with PIO data-in phase
  */
-static ide_startstop_t task_in_intr (ide_drive_t *drive)
+static ide_startstop_t task_in_intr (struct ata_device *drive, struct request *rq)
 {
-	byte stat		= GET_STAT();
-	struct request *rq	= HWGROUP(drive)->rq;
-	char *pBuf		= NULL;
+	u8 stat	= GET_STAT();
+	char *pBuf = NULL;
 	unsigned long flags;
 
 	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
@@ -554,7 +549,7 @@
 		}
 		if (!(stat & BUSY_STAT)) {
 			DTF("task_in_intr to Soon wait for next interrupt\n");
-			ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL);
+			ide_set_handler(drive, task_in_intr, WAIT_CMD, NULL);
 			return ide_started;
 		}
 	}
@@ -572,18 +567,18 @@
 	 */
 	if (--rq->current_nr_sectors <= 0) {
 		DTF("Request Ended stat: %02x\n", GET_STAT());
-		if (!ide_end_request(drive, 1))
+		if (!ide_end_request(drive, rq, 1))
 			return ide_stopped;
 	}
 
 	/*
 	 * still data left to transfer
 	 */
-	ide_set_handler(drive, &task_in_intr,  WAIT_CMD, NULL);
+	ide_set_handler(drive, task_in_intr,  WAIT_CMD, NULL);
 	return ide_started;
 }
 
-static ide_startstop_t pre_task_out_intr(ide_drive_t *drive, struct request *rq)
+static ide_startstop_t pre_task_out_intr(struct ata_device *drive, struct request *rq)
 {
 	struct ata_taskfile *args = rq->special;
 	ide_startstop_t startstop;
@@ -604,7 +599,7 @@
 		ide_unmap_rq(rq, buf, &flags);
 	} else {
 		ata_poll_drive_ready(drive);
-		return args->handler(drive);
+		return args->handler(drive, rq);
 	}
 	return ide_started;
 }
@@ -612,22 +607,20 @@
 /*
  * Handler for command with PIO data-out phase
  */
-static ide_startstop_t task_out_intr(ide_drive_t *drive)
+static ide_startstop_t task_out_intr(struct ata_device *drive, struct request *rq)
 {
-	byte stat		= GET_STAT();
-	struct request *rq	= HWGROUP(drive)->rq;
-	char *pBuf		= NULL;
+	u8 stat = GET_STAT();
+	char *pBuf = NULL;
 	unsigned long flags;
 
 	if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat))
 		return ide_error(drive, "task_out_intr", stat);
 
 	if (!rq->current_nr_sectors)
-		if (!ide_end_request(drive, 1))
+		if (!ide_end_request(drive, rq, 1))
 			return ide_stopped;
 
 	if ((rq->current_nr_sectors==1) ^ (stat & DRQ_STAT)) {
-		rq = HWGROUP(drive)->rq;
 		pBuf = ide_map_rq(rq, &flags);
 		DTF("write: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors);
 
@@ -644,15 +637,14 @@
 /*
  * Handler for command with Read Multiple
  */
-static ide_startstop_t task_mulin_intr(ide_drive_t *drive)
+static ide_startstop_t task_mulin_intr(struct ata_device *drive, struct request *rq)
 {
-	unsigned int		msect, nsect;
-	byte stat		= GET_STAT();
-	struct request *rq	= HWGROUP(drive)->rq;
-	char *pBuf		= NULL;
+	u8 stat;
+	char *pBuf = NULL;
+	unsigned int msect, nsect;
 	unsigned long flags;
 
-	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
+	if (!OK_STAT(stat = GET_STAT(),DATA_READY,BAD_R_STAT)) {
 		if (stat & (ERR_STAT|DRQ_STAT)) {
 			return ide_error(drive, "task_mulin_intr", stat);
 		}
@@ -679,7 +671,7 @@
 		rq->current_nr_sectors -= nsect;
 		msect -= nsect;
 		if (!rq->current_nr_sectors) {
-			if (!ide_end_request(drive, 1))
+			if (!ide_end_request(drive, rq, 1))
 				return ide_stopped;
 		}
 	} while (msect);
@@ -865,6 +857,7 @@
 			return;
 
 		case WIN_NOP:
+			args->handler = task_no_data_intr;
 			args->command_type = IDE_DRIVE_TASK_NO_DATA;
 			return;
 
diff -Nru a/drivers/ide/ide.c b/drivers/ide/ide.c
--- a/drivers/ide/ide.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/ide/ide.c	Tue Apr 30 17:10:25 2002
@@ -285,7 +285,7 @@
 	hwif->bus_state = BUSSTATE_ON;
 
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
-		ide_drive_t *drive = &hwif->drives[unit];
+		struct ata_device *drive = &hwif->drives[unit];
 
 		drive->type			= ATA_DISK;
 		drive->select.all		= (unit<<4)|0xa0;
@@ -369,14 +369,12 @@
 	return 0;	/* no, it is not a flash memory card */
 }
 
-int __ide_end_request(struct ata_device *drive, int uptodate, int nr_secs)
+int __ide_end_request(struct ata_device *drive, struct request *rq, int uptodate, int nr_secs)
 {
-	struct request *rq;
 	unsigned long flags;
 	int ret = 1;
 
 	spin_lock_irqsave(&ide_lock, flags);
-	rq = HWGROUP(drive)->rq;
 
 	BUG_ON(!(rq->flags & REQ_STARTED));
 
@@ -394,7 +392,7 @@
 
 	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
 		drive->state = 0;
-		drive->channel->dmaproc(ide_dma_on, drive);
+		drive->channel->udma(ide_dma_on, drive, rq);
 	}
 
 	if (!end_that_request_first(rq, uptodate, nr_secs)) {
@@ -416,8 +414,8 @@
  * timer is started to prevent us from waiting forever in case
  * something goes wrong (see the ide_timer_expiry() handler later on).
  */
-void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler,
-		      unsigned int timeout, ide_expiry_t *expiry)
+void ide_set_handler(struct ata_device *drive, ata_handler_t handler,
+		      unsigned long timeout, ata_expiry_t expiry)
 {
 	unsigned long flags;
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
@@ -434,7 +432,7 @@
 	spin_unlock_irqrestore(&ide_lock, flags);
 }
 
-static void ata_pre_reset(ide_drive_t *drive)
+static void ata_pre_reset(struct ata_device *drive)
 {
 	if (ata_ops(drive) && ata_ops(drive)->pre_reset)
 		ata_ops(drive)->pre_reset(drive);
@@ -444,13 +442,13 @@
 
 	/* check the DMA crc count */
 	if (drive->crc_count) {
-		drive->channel->dmaproc(ide_dma_off_quietly, drive);
+		drive->channel->udma(ide_dma_off_quietly, drive, NULL);
 		if ((drive->channel->speedproc) != NULL)
 		        drive->channel->speedproc(drive, ide_auto_reduce_xfer(drive));
 		if (drive->current_speed >= XFER_SW_DMA_0)
-			drive->channel->dmaproc(ide_dma_on, drive);
+			drive->channel->udma(ide_dma_on, drive, NULL);
 	} else
-		drive->channel->dmaproc(ide_dma_off, drive);
+		drive->channel->udma(ide_dma_off, drive, NULL);
 }
 
 /*
@@ -509,19 +507,21 @@
 /*
  * This is called exactly *once* for each channel.
  */
-void ide_geninit(struct ata_channel *hwif)
+void ide_geninit(struct ata_channel *ch)
 {
 	unsigned int unit;
-	struct gendisk *gd = hwif->gd;
+	struct gendisk *gd = ch->gd;
 
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
-		ide_drive_t *drive = &hwif->drives[unit];
+		struct ata_device *drive = &ch->drives[unit];
 
 		if (!drive->present)
 			continue;
+
 		if (drive->type != ATA_DISK && drive->type != ATA_FLOPPY)
 			continue;
-		register_disk(gd,mk_kdev(hwif->major,unit<<PARTN_BITS),
+
+		register_disk(gd,mk_kdev(ch->major,unit<<PARTN_BITS),
 #ifdef CONFIG_BLK_DEV_ISAPNP
 			(drive->forced_geom && drive->noprobe) ? 1 :
 #endif
@@ -536,7 +536,7 @@
  * operation. If the drive has not yet responded, and we have not yet hit our
  * maximum waiting time, then the timer is restarted for another 50ms.
  */
-static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
+static ide_startstop_t atapi_reset_pollfunc(struct ata_device *drive, struct request *__rq)
 {
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 	byte stat;
@@ -548,8 +548,7 @@
 		printk("%s: ATAPI reset complete\n", drive->name);
 	} else {
 		if (time_before(jiffies, hwgroup->poll_timeout)) {
-			BUG_ON(HWGROUP(drive)->handler);
-			ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL);
+			ide_set_handler (drive, atapi_reset_pollfunc, HZ/20, NULL);
 			return ide_started;	/* continue polling */
 		}
 		hwgroup->poll_timeout = 0;	/* end of polling */
@@ -557,6 +556,7 @@
 		return do_reset1 (drive, 1);	/* do it the old fashioned way */
 	}
 	hwgroup->poll_timeout = 0;	/* done polling */
+
 	return ide_stopped;
 }
 
@@ -565,7 +565,7 @@
  * If the drives have not yet responded, and we have not yet hit our maximum
  * waiting time, then the timer is restarted for another 50ms.
  */
-static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
+static ide_startstop_t reset_pollfunc(struct ata_device *drive, struct request *__rq)
 {
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 	struct ata_channel *hwif = drive->channel;
@@ -573,8 +573,7 @@
 
 	if (!OK_STAT(stat=GET_STAT(), 0, BUSY_STAT)) {
 		if (time_before(jiffies, hwgroup->poll_timeout)) {
-			BUG_ON(HWGROUP(drive)->handler);
-			ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL);
+			ide_set_handler(drive, reset_pollfunc, HZ/20, NULL);
 			return ide_started;	/* continue polling */
 		}
 		printk("%s: reset timed-out, status=0x%02x\n", hwif->name, stat);
@@ -589,7 +588,7 @@
 
 #if FANCY_STATUS_DUMPS
 			u8 val;
-			static const char *messages[5] = {
+			static char *messages[5] = {
 				" passed",
 				" formatter device",
 				" sector buffer",
@@ -645,11 +644,10 @@
 		ata_pre_reset(drive);
 		SELECT_DRIVE(hwif,drive);
 		udelay (20);
-		OUT_BYTE (WIN_SRST, IDE_COMMAND_REG);
+		OUT_BYTE(WIN_SRST, IDE_COMMAND_REG);
 		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-		BUG_ON(HWGROUP(drive)->handler);
-		ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL);
-		__restore_flags (flags);	/* local CPU only */
+		ide_set_handler(drive, atapi_reset_pollfunc, HZ/20, NULL);
+		__restore_flags(flags);	/* local CPU only */
 		return ide_started;
 	}
 
@@ -682,8 +680,7 @@
 	}
 	udelay(10);			/* more than enough time */
 	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-	BUG_ON(HWGROUP(drive)->handler);
-	ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
+	ide_set_handler(drive, reset_pollfunc, HZ/20, NULL);
 
 	/*
 	 * Some weird controller like resetting themselves to a strange
@@ -912,9 +909,9 @@
 
 	if (rq->errors >= ERROR_MAX) {
 		if (ata_ops(drive) && ata_ops(drive)->end_request)
-			ata_ops(drive)->end_request(drive, 0);
+			ata_ops(drive)->end_request(drive, rq, 0);
 		else
-			ide_end_request(drive, 0);
+			ide_end_request(drive, rq, 0);
 	} else {
 		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
 			++rq->errors;
@@ -930,9 +927,8 @@
 /*
  * 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, ata_handler_t handler)
 {
-	BUG_ON(HWGROUP(drive)->handler);
 	ide_set_handler (drive, handler, WAIT_CMD, NULL);
 	if (IDE_CONTROL_REG)
 		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* clear nIEN */
@@ -944,9 +940,8 @@
 /*
  * Invoked on completion of a special DRIVE_CMD.
  */
-static ide_startstop_t drive_cmd_intr(ide_drive_t *drive)
+static ide_startstop_t drive_cmd_intr(struct ata_device *drive, struct request *rq)
 {
-	struct request *rq = HWGROUP(drive)->rq;
 	u8 *args = rq->buffer;
 	u8 stat = GET_STAT();
 	int retries = 10;
@@ -1135,7 +1130,7 @@
 		if (ata_ops(drive)->do_request)
 			return ata_ops(drive)->do_request(drive, rq, block);
 		else {
-			ide_end_request(drive, 0);
+			ide_end_request(drive, rq, 0);
 			return ide_stopped;
 		}
 	}
@@ -1149,9 +1144,9 @@
 
 kill_rq:
 	if (ata_ops(drive) && ata_ops(drive)->end_request)
-		ata_ops(drive)->end_request(drive, 0);
+		ata_ops(drive)->end_request(drive, rq, 0);
 	else
-		ide_end_request(drive, 0);
+		ide_end_request(drive, rq, 0);
 
 	return ide_stopped;
 
@@ -1195,32 +1190,226 @@
 	drive->PADAM_sleep = timeout + jiffies;
 }
 
+
 /*
- * Select the next drive which will be serviced.
+ * Determine the longes sleep time for the devices in our hwgroup.
  */
-static struct ata_device *choose_drive(struct ata_device *cur)
+static unsigned long longest_sleep(struct ata_channel *channel)
 {
-	struct ata_device *drive = cur;
-	struct ata_device *best = NULL;
+	unsigned long sleep = 0;
+	int i;
 
-	do {
-		if (!list_empty(&drive->queue.queue_head)
-		&& (!drive->PADAM_sleep	|| time_after_eq(drive->PADAM_sleep, jiffies))) {
-			if (!best
-			 || (drive->PADAM_sleep && (!best->PADAM_sleep || time_after(best->PADAM_sleep, drive->PADAM_sleep)))
-			 || (!best->PADAM_sleep && time_after(best->PADAM_service_start + 2 * best->PADAM_service_time, drive->PADAM_service_start + 2 * drive->PADAM_service_time)))
+	for (i = 0; i < MAX_HWIFS; ++i) {
+		int unit;
+		struct ata_channel *ch = &ide_hwifs[i];
+
+		if (!ch->present)
+			continue;
+
+		if (ch->hwgroup != channel->hwgroup)
+			continue;
+
+		for (unit = 0; unit < MAX_DRIVES; ++unit) {
+			struct ata_device *drive = &ch->drives[unit];
+
+			if (!drive->present)
+				continue;
+
+			/* This device is sleeping and waiting to be serviced
+			 * later than any other device we checked thus far.
+			 */
+			if (drive->PADAM_sleep && (!sleep || time_after(sleep, drive->PADAM_sleep)))
+				sleep = drive->PADAM_sleep;
+		}
+	}
+
+	return sleep;
+}
+
+/*
+ * Select the next device which will be serviced.
+ */
+static struct ata_device *choose_urgent_device(struct ata_channel *channel)
+{
+	struct ata_device *choice = NULL;
+	unsigned long sleep = 0;
+	int i;
+
+	for (i = 0; i < MAX_HWIFS; ++i) {
+		int unit;
+		struct ata_channel *ch = &ide_hwifs[i];
+
+		if (!ch->present)
+			continue;
+
+		if (ch->hwgroup != channel->hwgroup)
+			continue;
+
+		for (unit = 0; unit < MAX_DRIVES; ++unit) {
+			struct ata_device *drive = &ch->drives[unit];
+
+			if (!drive->present)
+				continue;
+
+			/* There are no request pending for this device.
+			 */
+			if (list_empty(&drive->queue.queue_head))
+				continue;
+
+			/* This device still want's to remain idle.
+			 */
+			if (drive->PADAM_sleep && time_after(jiffies, drive->PADAM_sleep))
+				continue;
+
+			/* Take this device, if there is no device choosen thus far or
+			 * it's more urgent.
+			 */
+			if (!choice || (drive->PADAM_sleep && (!choice->PADAM_sleep || time_after(choice->PADAM_sleep, drive->PADAM_sleep))))
 			{
 				if (!blk_queue_plugged(&drive->queue))
-					best = drive;
+					choice = drive;
 			}
 		}
-		drive = drive->next;
-	} while (drive != cur);
-	return best;
+	}
+
+	if (choice)
+		return choice;
+
+	channel->hwgroup->rq = NULL;
+	sleep = longest_sleep(channel);
+
+	if (sleep) {
+
+		/*
+		 * Take a short snooze, and then wake up again.  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 (timer_pending(&channel->hwgroup->timer))
+			printk(KERN_ERR "ide_set_handler: timer already active\n");
+#endif
+		set_bit(IDE_SLEEP, &channel->hwgroup->flags);
+		mod_timer(&channel->hwgroup->timer, sleep);
+		/* we purposely leave hwgroup busy while sleeping */
+	} else {
+		/* Ugly, but how can we sleep for the lock otherwise? perhaps
+		 * from tq_disk? */
+		ide_release_lock(&irq_lock);/* for atari only */
+		clear_bit(IDE_BUSY, &channel->hwgroup->flags);
+	}
+
+	return NULL;
+}
+
+
+/* Place holders for later expansion of functionality.
+ */
+#define ata_pending_commands(drive)	(0)
+#define ata_can_queue(drive)		(1)
+
+/*
+ * Feed commands to a drive until it barfs.  Called with ide_lock/DRIVE_LOCK
+ * held and busy channel.
+ */
+
+static void queue_commands(struct ata_device *drive, int masked_irq)
+{
+	ide_hwgroup_t *hwgroup = drive->channel->hwgroup;
+	ide_startstop_t startstop = -1;
+
+	for (;;) {
+		struct request *rq = NULL;
+
+		if (!test_bit(IDE_BUSY, &hwgroup->flags))
+			printk(KERN_ERR"%s: hwgroup not busy while queueing\n", drive->name);
+
+		/* Abort early if we can't queue another command. for non
+		 * tcq, ata_can_queue is always 1 since we never get here
+		 * unless the drive is idle.
+		 */
+		if (!ata_can_queue(drive)) {
+			if (!ata_pending_commands(drive))
+				clear_bit(IDE_BUSY, &hwgroup->flags);
+			break;
+		}
+
+		drive->PADAM_sleep = 0;
+
+		if (test_bit(IDE_DMA, &hwgroup->flags)) {
+			printk("ide_do_request: DMA in progress...\n");
+			break;
+		}
+
+		/* There's a small window between where the queue could be
+		 * replugged while we are in here when using tcq (in which
+		 * case the queue is probably empty anyways...), so check
+		 * and leave if appropriate. When not using tcq, this is
+		 * still a severe BUG!
+		 */
+		if (blk_queue_plugged(&drive->queue)) {
+			BUG();
+			break;
+		}
+
+		if (!(rq = elv_next_request(&drive->queue))) {
+			if (!ata_pending_commands(drive))
+				clear_bit(IDE_BUSY, &hwgroup->flags);
+			hwgroup->rq = NULL;
+			break;
+		}
+
+		/* If there are queued commands, we can't start a non-fs
+		 * request (really, a non-queuable command) until the
+		 * queue is empty.
+		 */
+		if (!(rq->flags & REQ_CMD) && ata_pending_commands(drive))
+			break;
+
+		hwgroup->rq = rq;
+
+		/* Some systems have trouble with IDE IRQs arriving while the
+		 * driver is still setting things up.  So, here we disable the
+		 * IRQ used by this interface while the request is being
+		 * started.  This may look bad at first, but pretty much the
+		 * same thing happens anyway when any interrupt comes in, IDE
+		 * or otherwise -- the kernel masks the IRQ while it is being
+		 * handled.
+		 */
+
+		if (masked_irq && drive->channel->irq != masked_irq)
+			disable_irq_nosync(drive->channel->irq);
+
+		spin_unlock(&ide_lock);
+		ide__sti();	/* allow other IRQs while we start this request */
+		startstop = start_request(drive, rq);
+
+		spin_lock_irq(&ide_lock);
+		if (masked_irq && drive->channel->irq != masked_irq)
+			enable_irq(drive->channel->irq);
+
+		/* command started, we are busy */
+		if (startstop == ide_started)
+			break;
+
+		/* start_request() can return either ide_stopped (no command
+		 * was started), ide_started (command started, don't queue
+		 * more), or ide_released (command started, try and queue
+		 * more).
+		 */
+#if 0
+		if (startstop == ide_stopped)
+			set_bit(IDE_BUSY, &hwgroup->flags);
+#endif
+
+	}
 }
 
 /*
- * Issue a new request to a drive from hwgroup.
+ * Issue a new request.
  * Caller must have already done spin_lock_irqsave(&ide_lock, ...)
  *
  * A hwgroup is a serialized group of IDE interfaces.  Usually there is
@@ -1249,115 +1438,43 @@
  * will start the next request from the queue.  If no more work remains,
  * the driver will clear the hwgroup->flags IDE_BUSY flag and exit.
  */
-static void ide_do_request(struct ata_channel *ch, int masked_irq)
+static void ide_do_request(struct ata_channel *channel, int masked_irq)
 {
-	ide_hwgroup_t *hwgroup = ch->hwgroup;
-	struct ata_device *drive;
-	ide_startstop_t	startstop;
-	struct request	*rq;
-
+	ide_hwgroup_t *hwgroup = channel->hwgroup;
 	ide_get_lock(&irq_lock, ata_irq_request, hwgroup);/* for atari only: POSSIBLY BROKEN HERE(?) */
 
 	__cli();	/* necessary paranoia: ensure IRQs are masked on local CPU */
 
 	while (!test_and_set_bit(IDE_BUSY, &hwgroup->flags)) {
-		drive = choose_drive(hwgroup->drive);
+		struct ata_channel *ch;
+		struct ata_device *drive;
 
-		if (drive == NULL) {
-			unsigned long sleep = 0;
+		/* this will clear IDE_BUSY, if appropriate */
+		drive = choose_urgent_device(channel);
 
-			hwgroup->rq = NULL;
+		if (!drive)
+			break;
 
-			drive = hwgroup->drive;
-			do {
-				if (drive->PADAM_sleep && (!sleep || time_after(sleep, drive->PADAM_sleep)))
-					sleep = drive->PADAM_sleep;
-
-				drive = drive->next;
-			} while (drive!= hwgroup->drive);
-
-			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 (timer_pending(&hwgroup->timer))
-					printk("ide_set_handler: timer already active\n");
-#endif
-				set_bit(IDE_SLEEP, &hwgroup->flags);
-				mod_timer(&hwgroup->timer, sleep);
-				/* we purposely leave hwgroup busy while sleeping */
-			} else {
-				/* Ugly, but how can we sleep for the lock
-				 * otherwise? perhaps from tq_disk? */
-				ide_release_lock(&irq_lock);/* for atari only */
-				clear_bit(IDE_BUSY, &hwgroup->flags);
-			}
-			return;		/* no more work for this hwgroup (for now) */
-		}
 		ch = drive->channel;
 
-		if (hwgroup->drive->channel->sharing_irq && ch != hwgroup->drive->channel && ch->io_ports[IDE_CONTROL_OFFSET]) {
+		if (hwgroup->XXX_drive->channel->sharing_irq && ch != hwgroup->XXX_drive->channel && ch->io_ports[IDE_CONTROL_OFFSET]) {
 			/* set nIEN for previous channel */
+			/* FIXME: check this! It appears to act on the current channel! */
 
 			if (ch->intrproc)
 				ch->intrproc(drive);
 			else
 				OUT_BYTE((drive)->ctl|2, ch->io_ports[IDE_CONTROL_OFFSET]);
 		}
-		hwgroup->drive = drive;
-		drive->PADAM_sleep = 0;
-		drive->PADAM_service_start = jiffies;
-
-		if (blk_queue_plugged(&drive->queue))
-			BUG();
-
-		/*
-		 * just continuing an interrupted request maybe
-		 */
-		rq = hwgroup->rq = elv_next_request(&drive->queue);
 
-		/*
-		 * Some systems have trouble with IDE IRQs arriving while the
-		 * driver is still setting things up.  So, here we disable the
-		 * IRQ used by this interface while the request is being
-		 * started.  This may look bad at first, but pretty much the
-		 * same thing happens anyway when any interrupt comes in, IDE
-		 * or otherwise -- the kernel masks the IRQ while it is being
-		 * handled.
+		/* Remember the last drive we where acting on.
 		 */
+		hwgroup->XXX_drive = drive;
 
-		if (masked_irq && ch->irq != masked_irq)
-			disable_irq_nosync(ch->irq);
-		spin_unlock(&ide_lock);
-		ide__sti();	/* allow other IRQs while we start this request */
-		startstop = start_request(drive, rq);
-		spin_lock_irq(&ide_lock);
-		if (masked_irq && ch->irq != masked_irq)
-			enable_irq(ch->irq);
-		if (startstop == ide_stopped)
-			clear_bit(IDE_BUSY, &hwgroup->flags);
+		queue_commands(drive, masked_irq);
 	}
 }
 
-/*
- * Returns the queue which corresponds to a given device.
- */
-request_queue_t *ide_get_queue(kdev_t dev)
-{
-	struct ata_channel *ch = (struct ata_channel *)blk_dev[major(dev)].data;
-
-	/* FIXME: ALLERT: This discriminates between master and slave! */
-	return &ch->drives[DEVICE_NR(dev) & 1].queue;
-}
-
 void do_ide_request(request_queue_t *q)
 {
 	ide_do_request(q->queuedata, 0);
@@ -1368,21 +1485,20 @@
  * retry the current request in PIO mode instead of risking tossing it
  * all away
  */
-void ide_dma_timeout_retry(ide_drive_t *drive)
+static void dma_timeout_retry(struct ata_device *drive, struct request *rq)
 {
-	struct ata_channel *hwif = drive->channel;
-	struct request *rq;
+	struct ata_channel *ch = drive->channel;
 
 	/*
 	 * end current dma transaction
 	 */
-	hwif->dmaproc(ide_dma_end, drive);
+	ch->udma(ide_dma_end, drive, rq);
 
 	/*
 	 * complain a little, later we might remove some of this verbosity
 	 */
 	printk("%s: timeout waiting for DMA\n", drive->name);
-	hwif->dmaproc(ide_dma_timeout, drive);
+	ch->udma(ide_dma_timeout, drive, rq);
 
 	/*
 	 * Disable dma for now, but remember that we did so because of
@@ -1391,13 +1507,12 @@
 	 */
 	drive->retry_pio++;
 	drive->state = DMA_PIO_RETRY;
-	hwif->dmaproc(ide_dma_off_quietly, drive);
+	ch->udma(ide_dma_off_quietly, drive, rq);
 
 	/*
 	 * un-busy drive etc (hwgroup->busy is cleared on return) and
 	 * make sure request is sane
 	 */
-	rq = HWGROUP(drive)->rq;
 	HWGROUP(drive)->rq = NULL;
 
 	rq->errors = 0;
@@ -1415,11 +1530,11 @@
  */
 void ide_timer_expiry(unsigned long data)
 {
-	ide_hwgroup_t	*hwgroup = (ide_hwgroup_t *) data;
-	ide_handler_t	*handler;
-	ide_expiry_t	*expiry;
-	unsigned long	flags;
-	unsigned long	wait;
+	ide_hwgroup_t *hwgroup = (ide_hwgroup_t *) data;
+	ata_handler_t *handler;
+	ata_expiry_t *expiry;
+	unsigned long flags;
+	unsigned long wait;
 
 	/*
 	 * A global lock protects timers etc -- shouldn't get contention
@@ -1441,7 +1556,7 @@
 		if (test_and_clear_bit(IDE_SLEEP, &hwgroup->flags))
 			clear_bit(IDE_BUSY, &hwgroup->flags);
 	} else {
-		struct ata_device *drive = hwgroup->drive;
+		struct ata_device *drive = hwgroup->XXX_drive;
 		if (!drive) {
 			printk("ide_timer_expiry: hwgroup->drive was NULL\n");
 			hwgroup->handler = NULL;
@@ -1454,7 +1569,7 @@
 				printk("%s: ide_timer_expiry: hwgroup was not busy??\n", drive->name);
 			if ((expiry = hwgroup->expiry) != NULL) {
 				/* continue */
-				if ((wait = expiry(drive)) != 0) {
+				if ((wait = expiry(drive, HWGROUP(drive)->rq)) != 0) {
 					/* reengage timer */
 					hwgroup->timer.expires  = jiffies + wait;
 					add_timer(&hwgroup->timer);
@@ -1477,22 +1592,21 @@
 #endif
 			__cli();	/* local CPU only, as if we were handling an interrupt */
 			if (hwgroup->poll_timeout != 0) {
-				startstop = handler(drive);
+				startstop = handler(drive, ch->hwgroup->rq);
 			} else if (drive_is_ready(drive)) {
 				if (drive->waiting_for_dma)
-					ch->dmaproc(ide_dma_lostirq, drive);
+					ch->udma(ide_dma_lostirq, drive, ch->hwgroup->rq);
 				(void) ide_ack_intr(ch);
 				printk("%s: lost interrupt\n", drive->name);
-				startstop = handler(drive);
+				startstop = handler(drive, ch->hwgroup->rq);
 			} else {
 				if (drive->waiting_for_dma) {
 					startstop = ide_stopped;
-					ide_dma_timeout_retry(drive);
+					dma_timeout_retry(drive, ch->hwgroup->rq);
 				} else
 					startstop = ide_error(drive, "irq timeout", GET_STAT());
 			}
 			set_recovery_timer(ch);
-			drive->PADAM_service_time = jiffies - drive->PADAM_service_start;
 			enable_irq(ch->irq);
 			spin_lock_irq(&ide_lock);
 			if (startstop == ide_stopped)
@@ -1500,7 +1614,7 @@
 		}
 	}
 
-	ide_do_request(hwgroup->drive->channel, 0);
+	ide_do_request(hwgroup->XXX_drive->channel, 0);
 
 	spin_unlock_irqrestore(&ide_lock, flags);
 }
@@ -1534,15 +1648,15 @@
 
 	for (i = 0; i < MAX_HWIFS; ++i) {
 		u8 stat;
-		struct ata_channel *tmp = &ide_hwifs[i];
+		struct ata_channel *ch = &ide_hwifs[i];
 
-		if (!tmp->present)
+		if (!ch->present)
 			continue;
 
-		if (tmp->irq != irq)
+		if (ch->irq != irq)
 			continue;
 
-		stat = IN_BYTE(tmp->io_ports[IDE_STATUS_OFFSET]);
+		stat = IN_BYTE(ch->io_ports[IDE_STATUS_OFFSET]);
 		if (!OK_STAT(stat, READY_STAT, BAD_STAT)) {
 			/* Try to not flood the console with msgs */
 			static unsigned long last_msgtime;
@@ -1552,14 +1666,14 @@
 			if (time_after(jiffies, last_msgtime + HZ)) {
 				last_msgtime = jiffies;
 				printk("%s: unexpected interrupt, status=0x%02x, count=%d\n",
-						tmp->name, stat, count);
+						ch->name, stat, count);
 			}
 		}
 	}
 }
 
 /*
- * entry point for all interrupts, caller does __cli() for us
+ * Entry point for all interrupts, caller does __cli() for us.
  */
 void ata_irq_request(int irq, void *data, struct pt_regs *regs)
 {
@@ -1568,7 +1682,7 @@
 
 	unsigned long flags;
 	struct ata_device *drive;
-	ide_handler_t *handler;
+	ata_handler_t *handler = hwgroup->handler;
 	ide_startstop_t startstop;
 
 	spin_lock_irqsave(&ide_lock, flags);
@@ -1576,7 +1690,7 @@
 	if (!ide_ack_intr(ch))
 		goto out_lock;
 
-	if ((handler = hwgroup->handler) == NULL || hwgroup->poll_timeout != 0) {
+	if (handler == NULL || hwgroup->poll_timeout != 0) {
 #if 0
 		printk(KERN_INFO "ide: unexpected interrupt %d %d\n", ch->unit, irq);
 #endif
@@ -1610,14 +1724,7 @@
 		}
 		goto out_lock;
 	}
-	drive = hwgroup->drive;
-	if (!drive) {
-		/*
-		 * This should NEVER happen, and there isn't much we could do
-		 * about it here.
-		 */
-		goto out_lock;
-	}
+	drive = hwgroup->XXX_drive;
 	if (!drive_is_ready(drive)) {
 		/*
 		 * This happens regularly when we share a PCI IRQ with another device.
@@ -1636,7 +1743,9 @@
 
 	if (ch->unmask)
 		ide__sti();	/* local CPU only */
-	startstop = handler(drive);		/* service this interrupt, may set handler for next interrupt */
+
+	/* service this interrupt, may set handler for next interrupt */
+	startstop = handler(drive, hwgroup->rq);
 	spin_lock_irq(&ide_lock);
 
 	/*
@@ -1647,7 +1756,6 @@
 	 * won't allow another of the same (on any CPU) until we return.
 	 */
 	set_recovery_timer(drive->channel);
-	drive->PADAM_service_time = jiffies - drive->PADAM_service_start;
 	if (startstop == ide_stopped) {
 		if (hwgroup->handler == NULL) {	/* paranoia */
 			clear_bit(IDE_BUSY, &hwgroup->flags);
@@ -1671,11 +1779,11 @@
 	int h;
 
 	for (h = 0; h < MAX_HWIFS; ++h) {
-		struct ata_channel *hwif = &ide_hwifs[h];
-		if (hwif->present && major == hwif->major) {
+		struct ata_channel *ch = &ide_hwifs[h];
+		if (ch->present && major == ch->major) {
 			int unit = DEVICE_NR(i_rdev);
 			if (unit < MAX_DRIVES) {
-				ide_drive_t *drive = &hwif->drives[unit];
+				struct ata_device *drive = &ch->drives[unit];
 				if (drive->present)
 					return drive;
 			}
@@ -1807,46 +1915,44 @@
  */
 void revalidate_drives(void)
 {
-	struct ata_channel *hwif;
-	ide_drive_t *drive;
-	int h;
+	int i;
 
-	for (h = 0; h < MAX_HWIFS; ++h) {
+	for (i = 0; i < MAX_HWIFS; ++i) {
 		int unit;
-		hwif = &ide_hwifs[h];
+		struct ata_channel *ch = &ide_hwifs[i];
+
 		for (unit = 0; unit < MAX_DRIVES; ++unit) {
-			drive = &ide_hwifs[h].drives[unit];
+			struct ata_device *drive = &ch->drives[unit];
+
 			if (drive->revalidate) {
 				drive->revalidate = 0;
 				if (!initializing)
-					ide_revalidate_disk(mk_kdev(hwif->major, unit<<PARTN_BITS));
+					ide_revalidate_disk(mk_kdev(ch->major, unit<<PARTN_BITS));
 			}
 		}
 	}
 }
 
-static void ide_probe_module(void)
-{
-	ideprobe_init();
-	revalidate_drives();
-}
-
 static void ide_driver_module (void)
 {
-	int index;
+	int i;
+
+	/* Don't reinit the probe if there is already one channel detected. */
 
-	for (index = 0; index < MAX_HWIFS; ++index)
-		if (ide_hwifs[index].present)
-			goto search;
-	ide_probe_module();
-search:
+	for (i = 0; i < MAX_HWIFS; ++i) {
+		if (ide_hwifs[i].present)
+			goto revalidate;
+	}
+
+	ideprobe_init();
 
+revalidate:
 	revalidate_drives();
 }
 
 static int ide_open(struct inode * inode, struct file * filp)
 {
-	ide_drive_t *drive;
+	struct ata_device *drive;
 
 	if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
 		return -ENXIO;
@@ -1908,7 +2014,7 @@
  */
 static int ide_release(struct inode * inode, struct file * file)
 {
-	ide_drive_t *drive;
+	struct ata_device *drive;
 
 	if (!(drive = get_info_ptr(inode->i_rdev)))
 		return 0;
@@ -1984,24 +2090,29 @@
 void ide_unregister(struct ata_channel *ch)
 {
 	struct gendisk *gd;
-	ide_drive_t *drive, *d;
+	struct ata_device *d;
 	ide_hwgroup_t *hwgroup;
 	int unit, i;
 	unsigned long flags;
 	unsigned int p, minor;
-	struct ata_channel old_hwif;
+	struct ata_channel old;
 	int n = 0;
 
 	spin_lock_irqsave(&ide_lock, flags);
+
 	if (!ch->present)
 		goto abort;
+
 	put_device(&ch->dev);
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
-		drive = &ch->drives[unit];
+		struct ata_device * drive = &ch->drives[unit];
+
 		if (!drive->present)
 			continue;
+
 		if (drive->busy || drive->usage)
 			goto abort;
+
 		if (ata_ops(drive)) {
 			if (ata_ops(drive)->cleanup) {
 				if (ata_ops(drive)->cleanup(drive))
@@ -2017,9 +2128,11 @@
 	 */
 	spin_unlock_irqrestore(&ide_lock, flags);
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
-		drive = &ch->drives[unit];
+		struct ata_device * drive = &ch->drives[unit];
+
 		if (!drive->present)
 			continue;
+
 		minor = drive->select.b.unit << PARTN_BITS;
 		for (p = 0; p < (1<<PARTN_BITS); ++p) {
 			if (drive->part[p].nr_sects > 0) {
@@ -2036,25 +2149,24 @@
 	hwif_unregister(ch);
 
 	/*
-	 * Remove us from the hwgroup, and free the hwgroup if we were the only
-	 * member.
+	 * Remove us from the hwgroup
 	 */
 
 	hwgroup = ch->hwgroup;
-	d = hwgroup->drive;
+	d = hwgroup->XXX_drive;
 	for (i = 0; i < MAX_DRIVES; ++i) {
-		drive = &ch->drives[i];
+		struct ata_device *drive = &ch->drives[i];
+
 		if (drive->de) {
 			devfs_unregister (drive->de);
 			drive->de = NULL;
 		}
 		if (!drive->present)
 			continue;
-		while (hwgroup->drive->next != drive)
-			hwgroup->drive = hwgroup->drive->next;
-		hwgroup->drive->next = drive->next;
-		if (hwgroup->drive == drive)
-			hwgroup->drive = NULL;
+
+		if (hwgroup->XXX_drive == drive)
+			hwgroup->XXX_drive = NULL;
+
 		if (drive->id != NULL) {
 			kfree(drive->id);
 			drive->id = NULL;
@@ -2063,8 +2175,10 @@
 		blk_cleanup_queue(&drive->queue);
 	}
 	if (d->present)
-		hwgroup->drive = d;
+		hwgroup->XXX_drive = d;
 
+	/* Free the hwgroup if we were the only member.
+	 */
 	n = 0;
 	for (i = 0; i < MAX_HWIFS; ++i) {
 		struct ata_channel *tmp = &ide_hwifs[i];
@@ -2108,40 +2222,41 @@
 	 * it.
 	 */
 
-	old_hwif = *ch;
+	old = *ch;
 	init_hwif_data(ch, ch->index);
-	ch->hwgroup = old_hwif.hwgroup;
-	ch->tuneproc = old_hwif.tuneproc;
-	ch->speedproc = old_hwif.speedproc;
-	ch->selectproc = old_hwif.selectproc;
-	ch->resetproc = old_hwif.resetproc;
-	ch->intrproc = old_hwif.intrproc;
-	ch->maskproc = old_hwif.maskproc;
-	ch->quirkproc = old_hwif.quirkproc;
-	ch->rwproc	= old_hwif.rwproc;
-	ch->ata_read = old_hwif.ata_read;
-	ch->ata_write = old_hwif.ata_write;
-	ch->atapi_read = old_hwif.atapi_read;
-	ch->atapi_write = old_hwif.atapi_write;
-	ch->dmaproc = old_hwif.dmaproc;
-	ch->busproc = old_hwif.busproc;
-	ch->bus_state = old_hwif.bus_state;
-	ch->dma_base = old_hwif.dma_base;
-	ch->dma_extra = old_hwif.dma_extra;
-	ch->config_data = old_hwif.config_data;
-	ch->select_data = old_hwif.select_data;
-	ch->proc = old_hwif.proc;
+	ch->hwgroup = old.hwgroup;
+	ch->tuneproc = old.tuneproc;
+	ch->speedproc = old.speedproc;
+	ch->selectproc = old.selectproc;
+	ch->resetproc = old.resetproc;
+	ch->intrproc = old.intrproc;
+	ch->maskproc = old.maskproc;
+	ch->quirkproc = old.quirkproc;
+	ch->rwproc	= old.rwproc;
+	ch->ata_read = old.ata_read;
+	ch->ata_write = old.ata_write;
+	ch->atapi_read = old.atapi_read;
+	ch->atapi_write = old.atapi_write;
+	ch->udma = old.udma;
+	ch->busproc = old.busproc;
+	ch->bus_state = old.bus_state;
+	ch->dma_base = old.dma_base;
+	ch->dma_extra = old.dma_extra;
+	ch->config_data = old.config_data;
+	ch->select_data = old.select_data;
+	ch->proc = old.proc;
+	/* FIXME: most propably this is always right:! */
 #ifndef CONFIG_BLK_DEV_IDECS
-	ch->irq = old_hwif.irq;
+	ch->irq = old.irq;
 #endif
-	ch->major = old_hwif.major;
-	ch->chipset = old_hwif.chipset;
-	ch->autodma = old_hwif.autodma;
-	ch->udma_four = old_hwif.udma_four;
+	ch->major = old.major;
+	ch->chipset = old.chipset;
+	ch->autodma = old.autodma;
+	ch->udma_four = old.udma_four;
 #ifdef CONFIG_BLK_DEV_IDEPCI
-	ch->pci_dev = old_hwif.pci_dev;
+	ch->pci_dev = old.pci_dev;
 #endif
-	ch->straight8 = old_hwif.straight8;
+	ch->straight8 = old.straight8;
 
 abort:
 	spin_unlock_irqrestore(&ide_lock, flags);
@@ -2222,10 +2337,12 @@
 	hwif->chipset = hw->chipset;
 
 	if (!initializing) {
-		ide_probe_module();
+		ideprobe_init();
+		revalidate_drives();
 #ifdef CONFIG_PROC_FS
 		create_proc_ide_interfaces();
 #endif
+		/* FIXME: Do we really have to call it second time here?! */
 		ide_driver_module();
 	}
 
@@ -2398,13 +2515,13 @@
 	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)
 		return -EPERM;
-	if (!drive->id || !(drive->id->capability & 1) || !drive->channel->dmaproc)
+	if (!drive->id || !(drive->id->capability & 1) || !drive->channel->udma)
 		return -EPERM;
-	if (drive->channel->dmaproc(arg ? ide_dma_on : ide_dma_off, drive))
+	if (drive->channel->udma(arg ? ide_dma_on : ide_dma_off, drive, NULL))
 		return -EIO;
 	return 0;
 }
@@ -3122,31 +3239,35 @@
 /****************************************************************************/
 
 /* This is the default end request function as well */
-int ide_end_request(ide_drive_t *drive, int uptodate)
+int ide_end_request(struct ata_device *drive, struct request *rq, int uptodate)
 {
-	return __ide_end_request(drive, uptodate, 0);
+	return __ide_end_request(drive, rq, uptodate, 0);
 }
 
 /*
- * Lookup IDE devices, which requested a particular driver
+ * Lookup ATA devices, which requested a particular driver.
  */
 ide_drive_t *ide_scan_devices(byte type, const char *name, struct ata_operations *driver, int n)
 {
 	unsigned int unit, index, i;
 
 	for (index = 0, i = 0; index < MAX_HWIFS; ++index) {
-		struct ata_channel *hwif = &ide_hwifs[index];
-		if (!hwif->present)
+		struct ata_channel *ch = &ide_hwifs[index];
+
+		if (!ch->present)
 			continue;
+
 		for (unit = 0; unit < MAX_DRIVES; ++unit) {
-			ide_drive_t *drive = &hwif->drives[unit];
+			struct ata_device *drive = &ch->drives[unit];
 			char *req = drive->driver_req;
+
 			if (*req && !strstr(name, req))
 				continue;
 			if (drive->present && drive->type == type && drive->driver == driver && ++i > n)
 				return drive;
 		}
 	}
+
 	return NULL;
 }
 
@@ -3173,7 +3294,7 @@
 	restore_flags(flags);		/* all CPUs */
 	/* FIXME: Check what this magic number is supposed to be about? */
 	if (drive->autotune != 2) {
-		if (drive->channel->dmaproc != NULL) {
+		if (drive->channel->udma) {
 
 			/*
 			 * Force DMAing for the beginning of the check.  Some
@@ -3183,12 +3304,24 @@
 			 *   PARANOIA!!!
 			 */
 
-			drive->channel->dmaproc(ide_dma_off_quietly, drive);
-			drive->channel->dmaproc(ide_dma_check, drive);
+			drive->channel->udma(ide_dma_off_quietly, drive, NULL);
+			drive->channel->udma(ide_dma_check, drive, NULL);
 		}
-		/* Only CD-ROMs and tape drives support DSC overlap. */
-		drive->dsc_overlap = (drive->next != drive
-				&& (drive->type == ATA_ROM || drive->type == ATA_TAPE));
+
+		/* Only CD-ROMs and tape drives support DSC overlap.  But only
+		 * if they are alone on a channel. */
+		if (drive->type == ATA_ROM || drive->type == ATA_TAPE) {
+			int single = 0;
+			int unit;
+
+			for (unit = 0; unit < MAX_DRIVES; ++unit)
+				if (drive->channel->drives[unit].present)
+					++single;
+
+			drive->dsc_overlap = (single == 1);
+		} else
+			drive->dsc_overlap = 0;
+
 	}
 	drive->revalidate = 1;
 	drive->suspend_reset = 0;
@@ -3286,7 +3419,6 @@
 EXPORT_SYMBOL(ide_lock);
 EXPORT_SYMBOL(drive_is_flashcard);
 EXPORT_SYMBOL(ide_timer_expiry);
-EXPORT_SYMBOL(ide_get_queue);
 EXPORT_SYMBOL(ide_add_generic_settings);
 EXPORT_SYMBOL(do_ide_request);
 /*
@@ -3326,9 +3458,7 @@
 
 static int ide_notify_reboot (struct notifier_block *this, unsigned long event, void *x)
 {
-	struct ata_channel *hwif;
-	ide_drive_t *drive;
-	int i, unit;
+	int i;
 
 	switch (event) {
 		case SYS_HALT:
@@ -3342,12 +3472,15 @@
 	printk("flushing ide devices: ");
 
 	for (i = 0; i < MAX_HWIFS; i++) {
-		hwif = &ide_hwifs[i];
-		if (!hwif->present)
+		int unit;
+		struct ata_channel *ch = &ide_hwifs[i];
+
+		if (!ch->present)
 			continue;
 
 		for (unit = 0; unit < MAX_DRIVES; ++unit) {
-			drive = &hwif->drives[unit];
+			struct ata_device *drive = &ch->drives[unit];
+
 			if (!drive->present)
 				continue;
 
diff -Nru a/drivers/ide/ns87415.c b/drivers/ide/ns87415.c
--- a/drivers/ide/ns87415.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/ide/ns87415.c	Tue Apr 30 17:10:25 2002
@@ -82,7 +82,7 @@
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-static int ns87415_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
+static int ns87415_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq)
 {
 	struct ata_channel *hwif = drive->channel;
 	byte		dma_stat;
@@ -98,16 +98,16 @@
 		case ide_dma_write:
 		case ide_dma_read:
 			ns87415_prepare_drive(drive, 1);	/* select DMA xfer */
-			if (!ide_dmaproc(func, drive))		/* use standard DMA stuff */
+			if (!ide_dmaproc(func, drive, rq))		/* use standard DMA stuff */
 				return 0;
 			ns87415_prepare_drive(drive, 0);	/* DMA failed: select PIO xfer */
 			return 1;
 		case ide_dma_check:
 			if (drive->type != ATA_DISK)
-				return ide_dmaproc(ide_dma_off_quietly, drive);
+				return ide_dmaproc(ide_dma_off_quietly, drive, rq);
 			/* Fallthrough... */
 		default:
-			return ide_dmaproc(func, drive);	/* use standard DMA stuff */
+			return ide_dmaproc(func, drive, rq);	/* use standard DMA stuff */
 	}
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
@@ -206,7 +206,7 @@
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (hwif->dma_base)
-		hwif->dmaproc = &ns87415_dmaproc;
+		hwif->udma = ns87415_dmaproc;
 #endif
 
 	hwif->selectproc = &ns87415_selectproc;
diff -Nru a/drivers/ide/pdc202xx.c b/drivers/ide/pdc202xx.c
--- a/drivers/ide/pdc202xx.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/ide/pdc202xx.c	Tue Apr 30 17:10:25 2002
@@ -929,7 +929,7 @@
 
 	if (id && (id->capability & 1) && hwif->autodma) {
 		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+		if (ide_dmaproc(ide_dma_bad_drive, drive, NULL)) {
 			dma_func = ide_dma_off;
 			goto fast_ata_pio;
 		}
@@ -951,7 +951,7 @@
 				if (dma_func != ide_dma_on)
 					goto no_dma_set;
 			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
+		} else if (ide_dmaproc(ide_dma_good_drive, drive, NULL)) {
 			if (id->eide_dma_time > 150) {
 				goto no_dma_set;
 			}
@@ -969,7 +969,7 @@
 		(void) config_chipset_for_pio(drive, 5);
 	}
 
-	return drive->channel->dmaproc(dma_func, drive);
+	return drive->channel->udma(dma_func, drive, NULL);
 }
 
 int pdc202xx_quirkproc (ide_drive_t *drive)
@@ -980,7 +980,7 @@
 /*
  * pdc202xx_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
  */
-int pdc202xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+int pdc202xx_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq)
 {
 	byte dma_stat		= 0;
 	byte sc1d		= 0;
@@ -1060,7 +1060,7 @@
 		default:
 			break;
 	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
+	return ide_dmaproc(func, drive, rq);	/* use standard DMA stuff */
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
@@ -1268,7 +1268,7 @@
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (hwif->dma_base) {
-		hwif->dmaproc = &pdc202xx_dmaproc;
+		hwif->udma = pdc202xx_dmaproc;
 		hwif->highmem = 1;
 		if (!noautodma)
 			hwif->autodma = 1;
diff -Nru a/drivers/ide/pdc4030.c b/drivers/ide/pdc4030.c
--- a/drivers/ide/pdc4030.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/ide/pdc4030.c	Tue Apr 30 17:10:25 2002
@@ -306,13 +306,12 @@
 /*
  * promise_read_intr() is the handler for disk read/multread interrupts
  */
-static ide_startstop_t promise_read_intr (ide_drive_t *drive)
+static ide_startstop_t promise_read_intr(struct ata_device *drive, struct request *rq)
 {
 	byte stat;
 	int total_remaining;
 	unsigned int sectors_left, sectors_avail, nsect;
 	unsigned long flags;
-	struct request *rq;
 	char *to;
 
 	if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
@@ -324,13 +323,11 @@
 		sectors_left = IN_BYTE(IDE_NSECTOR_REG);
 		IN_BYTE(IDE_SECTOR_REG);
 	} while (IN_BYTE(IDE_NSECTOR_REG) != sectors_left);
-	rq = HWGROUP(drive)->rq;
 	sectors_avail = rq->nr_sectors - sectors_left;
 	if (!sectors_avail)
 		goto read_again;
 
 read_next:
-	rq = HWGROUP(drive)->rq;
 	nsect = rq->current_nr_sectors;
 	if (nsect > sectors_avail)
 		nsect = sectors_avail;
@@ -348,7 +345,7 @@
 	rq->nr_sectors -= nsect;
 	total_remaining = rq->nr_sectors;
 	if ((rq->current_nr_sectors -= nsect) <= 0) {
-		ide_end_request(drive, 1);
+		ide_end_request(drive, rq, 1);
 	}
 /*
  * Now the data has been read in, do the following:
@@ -368,7 +365,7 @@
 		if (stat & DRQ_STAT)
 			goto read_again;
 		if (stat & BUSY_STAT) {
-			ide_set_handler (drive, &promise_read_intr, WAIT_CMD, NULL);
+			ide_set_handler(drive, promise_read_intr, WAIT_CMD, NULL);
 #ifdef DEBUG_READ
 			printk(KERN_DEBUG "%s: promise_read: waiting for"
 			       "interrupt\n", drive->name);
@@ -383,22 +380,19 @@
 }
 
 /*
- * promise_complete_pollfunc()
  * This is the polling function for waiting (nicely!) until drive stops
  * being busy. It is invoked at the end of a write, after the previous poll
  * has finished.
  *
  * Once not busy, the end request is called.
  */
-static ide_startstop_t promise_complete_pollfunc(ide_drive_t *drive)
+static ide_startstop_t promise_complete_pollfunc(struct ata_device *drive, struct request *rq)
 {
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	struct request *rq = hwgroup->rq;
 
 	if (GET_STAT() & BUSY_STAT) {
 		if (time_before(jiffies, hwgroup->poll_timeout)) {
-			BUG_ON(HWGROUP(drive)->handler);
-			ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
+			ide_set_handler(drive, promise_complete_pollfunc, HZ/100, NULL);
 			return ide_started; /* continue polling... */
 		}
 		hwgroup->poll_timeout = 0;
@@ -411,7 +405,7 @@
 #ifdef DEBUG_WRITE
 	printk(KERN_DEBUG "%s: Write complete - end_request\n", drive->name);
 #endif
-	__ide_end_request(drive, 1, rq->nr_sectors);
+	__ide_end_request(drive, rq, 1, rq->nr_sectors);
 
 	return ide_stopped;
 }
@@ -427,11 +421,8 @@
  * full "mcount" number of sectors, so we must make sure we update the
  * state _before_ we output the final part of the data!
  */
-int promise_multwrite (ide_drive_t *drive, unsigned int mcount)
+int promise_multwrite(struct ata_device *drive, struct request *rq, unsigned int mcount)
 {
-	ide_hwgroup_t   *hwgroup= HWGROUP(drive);
-	struct request  *rq = &hwgroup->wrq;
-
 	do {
 		char *buffer;
 		int nsect = rq->current_nr_sectors;
@@ -474,14 +465,13 @@
 /*
  * promise_write_pollfunc() is the handler for disk write completion polling.
  */
-static ide_startstop_t promise_write_pollfunc (ide_drive_t *drive)
+static ide_startstop_t promise_write_pollfunc(struct ata_device *drive, struct request *rq)
 {
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 
 	if (IN_BYTE(IDE_NSECTOR_REG) != 0) {
 		if (time_before(jiffies, hwgroup->poll_timeout)) {
-			BUG_ON(HWGROUP(drive)->handler);
-			ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);
+			ide_set_handler(drive, promise_write_pollfunc, HZ/100, NULL);
 			return ide_started; /* continue polling... */
 		}
 		hwgroup->poll_timeout = 0;
@@ -492,10 +482,9 @@
 	/*
 	 * Now write out last 4 sectors and poll for not BUSY
 	 */
-	promise_multwrite(drive, 4);
+	promise_multwrite(drive, rq, 4);
 	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-	BUG_ON(HWGROUP(drive)->handler);
-	ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
+	ide_set_handler(drive, promise_complete_pollfunc, HZ/100, NULL);
 #ifdef DEBUG_WRITE
 	printk(KERN_DEBUG "%s: Done last 4 sectors - status = %02x\n",
 		drive->name, GET_STAT());
@@ -510,10 +499,9 @@
  * before the final 4 sectors are transferred. There is no interrupt generated
  * on writes (at least on the DC4030VL-2), we just have to poll for NOT BUSY.
  */
-static ide_startstop_t promise_write (ide_drive_t *drive)
+static ide_startstop_t promise_write(struct ata_device *drive, struct request *rq)
 {
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	struct request *rq = &hwgroup->wrq;
 
 #ifdef DEBUG_WRITE
 	printk(KERN_DEBUG "%s: promise_write: sectors(%ld-%ld), "
@@ -526,22 +514,20 @@
 	 * the polling strategy as defined above.
 	 */
 	if (rq->nr_sectors > 4) {
-		if (promise_multwrite(drive, rq->nr_sectors - 4))
+		if (promise_multwrite(drive, rq, rq->nr_sectors - 4))
 			return ide_stopped;
 		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-		BUG_ON(HWGROUP(drive)->handler);
-		ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);
+		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.
 	 */
-		if (promise_multwrite(drive, rq->nr_sectors))
+		if (promise_multwrite(drive, rq, rq->nr_sectors))
 			return ide_stopped;
 		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-		BUG_ON(HWGROUP(drive)->handler);
-		ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
+		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());
@@ -555,9 +541,8 @@
  * 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.
  */
-ide_startstop_t do_pdc4030_io(ide_drive_t *drive, struct ata_taskfile *task)
+ide_startstop_t do_pdc4030_io(struct ata_device *drive, struct ata_taskfile *task, struct request *rq)
 {
-	struct request *rq = HWGROUP(drive)->rq;
 	struct hd_drive_task_hdr *taskfile = &task->taskfile;
 	unsigned long timeout;
 	byte stat;
@@ -565,7 +550,7 @@
 	/* Check that it's a regular command. If not, bomb out early. */
 	if (!(rq->flags & REQ_CMD)) {
 		blk_dump_rq_flags(rq, "pdc4030 bad flags");
-		ide_end_request(drive, 0);
+		ide_end_request(drive, rq, 0);
 		return ide_stopped;
 	}
 
@@ -600,15 +585,14 @@
 			stat=GET_STAT();
 			if (stat & DRQ_STAT) {
 				udelay(1);
-				return promise_read_intr(drive);
+				return promise_read_intr(drive, rq);
 			}
 			if (IN_BYTE(IDE_SELECT_REG) & 0x01) {
 #ifdef DEBUG_READ
 				printk(KERN_DEBUG "%s: read: waiting for "
 				                  "interrupt\n", drive->name);
 #endif
-				BUG_ON(HWGROUP(drive)->handler);
-				ide_set_handler(drive, &promise_read_intr, WAIT_CMD, NULL);
+				ide_set_handler(drive, promise_read_intr, WAIT_CMD, NULL);
 				return ide_started;
 			}
 			udelay(1);
@@ -634,39 +618,34 @@
 		}
 		if (!drive->channel->unmask)
 			__cli();	/* local CPU only */
-		HWGROUP(drive)->wrq = *rq; /* scratchpad */
-		return promise_write(drive);
+		return promise_write(drive, rq);
 	}
 
 	default:
 		printk(KERN_ERR "pdc4030: command not READ or WRITE! Huh?\n");
-		ide_end_request(drive, 0);
+		ide_end_request(drive, rq, 0);
 		return ide_stopped;
 	}
 }
 
-ide_startstop_t promise_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+ide_startstop_t promise_rw_disk(struct ata_device *drive, struct request *rq, sector_t block)
 {
-	struct hd_drive_task_hdr taskfile;
 	struct ata_taskfile args;
 
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&args, 0, sizeof(args));
 
 	/* The four drives on the two logical (one physical) interfaces
 	   are distinguished by writing the drive number (0-3) to the
 	   Feature register.
 	   FIXME: Is promise_selectproc now redundant??
 	*/
-	taskfile.feature	= (drive->channel->unit << 1) + drive->select.b.unit;
-	taskfile.sector_count	= rq->nr_sectors;
-	taskfile.sector_number	= block;
-	taskfile.low_cylinder	= (block>>=8);
-	taskfile.high_cylinder	= (block>>=8);
-	taskfile.device_head	= ((block>>8)&0x0f)|drive->select.all;
-	taskfile.command	= (rq_data_dir(rq)==READ)?PROMISE_READ:PROMISE_WRITE;
-
-	args.taskfile = taskfile;
-	memset(&args.hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+	args.taskfile.feature		= (drive->channel->unit << 1) + drive->select.b.unit;
+	args.taskfile.sector_count	= rq->nr_sectors;
+	args.taskfile.sector_number	= block;
+	args.taskfile.low_cylinder	= (block>>=8);
+	args.taskfile.high_cylinder	= (block>>=8);
+	args.taskfile.device_head	= ((block>>8)&0x0f)|drive->select.all;
+	args.taskfile.command		= (rq_data_dir(rq)==READ)?PROMISE_READ:PROMISE_WRITE;
 
 	ide_cmd_type_parser(&args);
 	/* We don't use the generic inerrupt handlers here? */
@@ -674,6 +653,6 @@
 	args.handler		= NULL;
 	rq->special		= &args;
 
-	return do_pdc4030_io(drive, &args);
+	return do_pdc4030_io(drive, &args, rq);
 }
 
diff -Nru a/drivers/ide/piix.c b/drivers/ide/piix.c
--- a/drivers/ide/piix.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/ide/piix.c	Tue Apr 30 17:10:25 2002
@@ -61,14 +61,19 @@
 #define PIIX_UDMA_NONE		0x00
 #define PIIX_UDMA_33		0x01
 #define PIIX_UDMA_66		0x02
-#define PIIX_UDMA_V66		0x03
-#define PIIX_UDMA_100		0x04
+#define PIIX_UDMA_100		0x03
+#define PIIX_UDMA_133		0x04
 #define PIIX_NO_SITRE		0x08	/* Chip doesn't have separate slave timing */
 #define PIIX_PINGPONG		0x10	/* Enable ping-pong buffers */
 #define PIIX_VICTORY		0x20	/* Efar Victory66 has a different UDMA setup */
 #define PIIX_CHECK_REV		0x40	/* May be a buggy revision of PIIX */
 #define PIIX_NODMA		0x80	/* Don't do DMA with this chip */
 
+#ifdef CONFIG_BLK_DEV_PIIX_TRY133	/* I think even the older ICHs should be able to do UDMA133 */
+#undef PIIX_UDMA_100
+#define PIIX_UDMA_100 PIIX_UDMA_133
+#endif
+
 /*
  * Intel IDE chips
  */
@@ -77,18 +82,20 @@
 	unsigned short id;
 	unsigned char flags;
 } piix_ide_chips[] = {
-	{ PCI_DEVICE_ID_INTEL_82801CA_11,	PIIX_UDMA_100 | PIIX_PINGPONG },                    /* Intel 82801CA ICH3 */
+	{ PCI_DEVICE_ID_INTEL_82801DB_9,	PIIX_UDMA_133 | PIIX_PINGPONG },                    /* Intel 82801DB ICH4 */
+	{ PCI_DEVICE_ID_INTEL_82801CA_11,	PIIX_UDMA_100 | PIIX_PINGPONG },                    /* Intel 82801CA ICH3/ICH3-S */
 	{ PCI_DEVICE_ID_INTEL_82801CA_10,	PIIX_UDMA_100 | PIIX_PINGPONG },                    /* Intel 82801CAM ICH3-M */
+	{ PCI_DEVICE_ID_INTEL_82801E_9,		PIIX_UDMA_100 | PIIX_PINGPONG },                    /* Intel 82801E C-ICH */
 	{ PCI_DEVICE_ID_INTEL_82801BA_9,	PIIX_UDMA_100 | PIIX_PINGPONG },                    /* Intel 82801BA ICH2 */
 	{ PCI_DEVICE_ID_INTEL_82801BA_8,	PIIX_UDMA_100 | PIIX_PINGPONG },                    /* Intel 82801BAM ICH2-M */
 	{ PCI_DEVICE_ID_INTEL_82801AB_1,	PIIX_UDMA_33  | PIIX_PINGPONG },                    /* Intel 82801AB ICH0 */
 	{ PCI_DEVICE_ID_INTEL_82801AA_1,	PIIX_UDMA_66  | PIIX_PINGPONG },                    /* Intel 82801AA ICH */
 	{ PCI_DEVICE_ID_INTEL_82372FB_1,	PIIX_UDMA_66 },	                                    /* Intel 82372FB PIIX5 */
 	{ PCI_DEVICE_ID_INTEL_82443MX_1,	PIIX_UDMA_33 },                                     /* Intel 82443MX MPIIX4 */
-	{ PCI_DEVICE_ID_INTEL_82371AB,		PIIX_UDMA_33 },                                     /* Intel 82371AB/EB PIIX4/4E */
+	{ PCI_DEVICE_ID_INTEL_82371AB,		PIIX_UDMA_33 },                                     /* Intel 82371AB/EB PIIX4/PIIX4E */
 	{ PCI_DEVICE_ID_INTEL_82371SB_1,	PIIX_UDMA_NONE },                                   /* Intel 82371SB PIIX3 */
 	{ PCI_DEVICE_ID_INTEL_82371FB_1,	PIIX_UDMA_NONE | PIIX_NO_SITRE | PIIX_CHECK_REV },  /* Intel 82371FB PIIX */
-	{ PCI_DEVICE_ID_EFAR_SLC90E66_1,	PIIX_UDMA_V66 | PIIX_VICTORY },                     /* Efar Victory66 */
+	{ PCI_DEVICE_ID_EFAR_SLC90E66_1,	PIIX_UDMA_66 | PIIX_VICTORY },                      /* Efar Victory66 */
 	{ 0 }
 };
 
@@ -97,7 +104,7 @@
 static unsigned int piix_80w;
 static unsigned int piix_clock;
 
-static char *piix_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA66", "UDMA100" };
+static char *piix_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100", "UDMA133" };
 
 /*
  * PIIX/ICH /proc entry.
@@ -318,20 +325,19 @@
 {
 	ide_drive_t *peer = drive->channel->drives + (~drive->dn & 1);
 	struct ata_timing t, p;
-	int err, T, UT, umul;
+	int err, T, UT, umul = 1;
 
 	if (speed != XFER_PIO_SLOW && speed != drive->current_speed)
 		if ((err = ide_config_drive_speed(drive, speed)))
 			return err;
 
-	umul =  min((speed > XFER_UDMA_4) ? 4 : ((speed > XFER_UDMA_2) ? 2 : 1),
-		piix_config->flags & PIIX_UDMA);
-
-	if (piix_config->flags & PIIX_VICTORY)
+	if (speed > XFER_UDMA_2 && (piix_config->flags & PIIX_UDMA) >= PIIX_UDMA_66)
 		umul = 2;
-
+	if (speed > XFER_UDMA_4 && (piix_config->flags & PIIX_UDMA) >= PIIX_UDMA_100)
+		umul = 4;
+	
 	T = 1000000000 / piix_clock;
-	UT = umul ? (T / umul) : 0;
+	UT = T / umul;
 
 	ata_timing_compute(drive, speed, &t, T, UT);
 
@@ -376,7 +382,7 @@
  * else to the default ide_dmaproc().
  */
 
-int piix_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
+int piix_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq)
 {
 
 	if (func == ide_dma_check) {
@@ -388,7 +394,8 @@
 			(piix_config->flags & PIIX_NODMA ? 0 : (XFER_SWDMA | XFER_MWDMA |
 			(piix_config->flags & PIIX_UDMA ? XFER_UDMA : 0) |
 			(w80 && (piix_config->flags & PIIX_UDMA) >= PIIX_UDMA_66 ? XFER_UDMA_66 : 0) |
-			(w80 && (piix_config->flags & PIIX_UDMA) >= PIIX_UDMA_100 ? XFER_UDMA_100 : 0))));
+			(w80 && (piix_config->flags & PIIX_UDMA) >= PIIX_UDMA_100 ? XFER_UDMA_100 : 0) |
+			(w80 && (piix_config->flags & PIIX_UDMA) >= PIIX_UDMA_133 ? XFER_UDMA_133 : 0))));
 
 		piix_set_drive(drive, speed);
 
@@ -397,7 +404,7 @@
 
 	}
 
-	return ide_dmaproc(func, drive);
+	return ide_dmaproc(func, drive, rq);
 }
 
 #endif /* CONFIG_BLK_DEV_IDEDMA */
@@ -458,15 +465,17 @@
 	switch (piix_config->flags & PIIX_UDMA) {
 
 		case PIIX_UDMA_66:
+			if (piix_config->flags && PIIX_VICTORY) {
+				pci_read_config_byte(dev, PIIX_IDESTAT, &t);
+				piix_80w = ((t & 2) ? 1 : 0) | ((t & 1) ? 2 : 0);
+				break;
+			}
+
 		case PIIX_UDMA_100:
+		case PIIX_UDMA_133:
 			pci_read_config_dword(dev, PIIX_IDECFG, &u);
 			piix_80w = ((u & 0x30) ? 1 : 0) | ((u & 0xc0) ? 2 : 0);
 			break;
-
-		case PIIX_UDMA_V66:
-			pci_read_config_byte(dev, PIIX_IDESTAT, &t);
-			piix_80w = ((t & 2) ? 1 : 0) | ((t & 1) ? 2 : 0);
-			break;
 	}
 
 /*
@@ -555,7 +564,7 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (hwif->dma_base) {
 		hwif->highmem = 1;
-		hwif->dmaproc = &piix_dmaproc;
+		hwif->udma = piix_dmaproc;
 #ifdef CONFIG_IDEDMA_AUTO
 		if (!noautodma)
 			hwif->autodma = 1;
diff -Nru a/drivers/ide/serverworks.c b/drivers/ide/serverworks.c
--- a/drivers/ide/serverworks.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/ide/serverworks.c	Tue Apr 30 17:10:25 2002
@@ -438,7 +438,7 @@
 
 	if (id && (id->capability & 1) && drive->channel->autodma) {
 		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+		if (ide_dmaproc(ide_dma_bad_drive, drive, NULL)) {
 			dma_func = ide_dma_off;
 			goto fast_ata_pio;
 		}
@@ -460,7 +460,7 @@
 				if (dma_func != ide_dma_on)
 					goto no_dma_set;
 			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
+		} else if (ide_dmaproc(ide_dma_good_drive, drive, NULL)) {
 			if (id->eide_dma_time > 150) {
 				goto no_dma_set;
 			}
@@ -477,10 +477,10 @@
 no_dma_set:
 		config_chipset_for_pio(drive);
 	}
-	return drive->channel->dmaproc(dma_func, drive);
+	return drive->channel->udma(dma_func, drive, NULL);
 }
 
-static int svwks_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
+static int svwks_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq)
 {
 	switch (func) {
 		case ide_dma_check:
@@ -489,10 +489,10 @@
 		{
 			struct ata_channel *hwif = drive->channel;
 			unsigned long dma_base		= hwif->dma_base;
-	
+
 			if(inb(dma_base+0x02)&1)
 			{
-#if 0		
+#if 0
 				int i;
 				printk(KERN_ERR "Curious - OSB4 thinks the DMA is still running.\n");
 				for(i=0;i<10;i++)
@@ -504,18 +504,18 @@
 					}
 					udelay(5);
 				}
-#endif		
+#endif
 				printk(KERN_CRIT "Serverworks OSB4 in impossible state.\n");
 				printk(KERN_CRIT "Disable UDMA or if you are using Seagate then try switching disk types\n");
 				printk(KERN_CRIT "on this controller. Please report this event to osb4-bug@ide.cabal.tm\n");
-#if 0		
+#if 0
 				/* Panic might sys_sync -> death by corrupt disk */
 				panic("OSB4: continuing might cause disk corruption.\n");
 #else
 				printk(KERN_CRIT "OSB4: continuing might cause disk corruption.\n");
 				while(1)
 					cpu_relax();
-#endif				
+#endif
 			}
 			/* and drop through */
 		}
@@ -523,7 +523,7 @@
 			break;
 	}
 	/* Other cases are done by generic IDE-DMA code. */
-	return ide_dmaproc(func, drive);
+	return ide_dmaproc(func, drive, rq);
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
@@ -645,7 +645,7 @@
 		if (!noautodma)
 			hwif->autodma = 1;
 #endif
-		hwif->dmaproc = &svwks_dmaproc;
+		hwif->udma = svwks_dmaproc;
 		hwif->highmem = 1;
 	} else {
 		hwif->autodma = 0;
diff -Nru a/drivers/ide/sis5513.c b/drivers/ide/sis5513.c
--- a/drivers/ide/sis5513.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/ide/sis5513.c	Tue Apr 30 17:10:25 2002
@@ -685,7 +685,7 @@
 
 	if (id && (id->capability & 1) && drive->channel->autodma) {
 		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+		if (ide_dmaproc(ide_dma_bad_drive, drive, NULL)) {
 			dma_func = ide_dma_off;
 			goto fast_ata_pio;
 		}
@@ -707,7 +707,7 @@
 				if (dma_func != ide_dma_on)
 					goto no_dma_set;
 			}
-		} else if ((ide_dmaproc(ide_dma_good_drive, drive)) &&
+		} else if ((ide_dmaproc(ide_dma_good_drive, drive, NULL)) &&
 			   (id->eide_dma_time > 150)) {
 			/* Consult the list of known "good" drives */
 			dma_func = config_chipset_for_dma(drive, 0);
@@ -723,11 +723,11 @@
 		(void) config_chipset_for_pio(drive, 5);
 	}
 
-	return drive->channel->dmaproc(dma_func, drive);
+	return drive->channel->udma(dma_func, drive, NULL);
 }
 
 /* initiates/aborts (U)DMA read/write operations on a drive. */
-int sis5513_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+int sis5513_dmaproc (ide_dma_action_t func, struct ata_device *drive, struct request *rq)
 {
 	switch (func) {
 		case ide_dma_check:
@@ -737,7 +737,7 @@
 		default:
 			break;
 	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
+	return ide_dmaproc(func, drive, rq);	/* use standard DMA stuff */
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
@@ -852,7 +852,7 @@
 		if (chipset_family > ATA_16) {
 			hwif->autodma = noautodma ? 0 : 1;
 			hwif->highmem = 1;
-			hwif->dmaproc = &sis5513_dmaproc;
+			hwif->udma = sis5513_dmaproc;
 		} else {
 #endif
 			hwif->autodma = 0;
diff -Nru a/drivers/ide/trm290.c b/drivers/ide/trm290.c
--- a/drivers/ide/trm290.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/ide/trm290.c	Tue Apr 30 17:10:25 2002
@@ -194,7 +194,6 @@
 			outw((count * 2) - 1, hwif->dma_base+2); /* start DMA */
 			if (drive->type != ATA_DISK)
 				return 0;
-			BUG_ON(HWGROUP(drive)->handler);
 			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
 			OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
 			return 0;
diff -Nru a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c
--- a/drivers/ide/via82cxxx.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/ide/via82cxxx.c	Tue Apr 30 17:10:25 2002
@@ -363,7 +363,7 @@
  * else to the default ide_dmaproc().
  */
 
-int via82cxxx_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
+int via82cxxx_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq)
 {
 
 	if (func == ide_dma_check) {
@@ -383,7 +383,7 @@
 			? ide_dma_on : ide_dma_off_quietly;
 	}
 
-	return ide_dmaproc(func, drive);
+	return ide_dmaproc(func, drive, rq);
 }
 
 #endif /* CONFIG_BLK_DEV_IDEDMA */
@@ -546,7 +546,7 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (hwif->dma_base) {
 		hwif->highmem = 1;
-		hwif->dmaproc = &via82cxxx_dmaproc;
+		hwif->udma = &via82cxxx_dmaproc;
 #ifdef CONFIG_IDEDMA_AUTO
 		if (!noautodma)
 			hwif->autodma = 1;
diff -Nru a/drivers/isdn/capi/Makefile b/drivers/isdn/capi/Makefile
--- a/drivers/isdn/capi/Makefile	Tue Apr 30 17:10:25 2002
+++ b/drivers/isdn/capi/Makefile	Tue Apr 30 17:10:25 2002
@@ -10,13 +10,13 @@
 
 # Multipart objects.
 
-kernelcapi-objs	:= kcapi.o
+kernelcapi-objs	:= kcapi.o capiutil.o
 
 # Ordering constraints: kernelcapi.o first
 
 # Each configuration option enables a list of files.
 
-obj-$(CONFIG_ISDN_CAPI)			+= kernelcapi.o capiutil.o
+obj-$(CONFIG_ISDN_CAPI)			+= kernelcapi.o
 obj-$(CONFIG_ISDN_CAPI_CAPI20)		+= capi.o 
 obj-$(CONFIG_ISDN_CAPI_CAPIDRV)		+= capidrv.o
 obj-$(CONFIG_ISDN_CAPI_CAPIFS)		+= capifs.o
diff -Nru a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c
--- a/drivers/isdn/capi/capidrv.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/isdn/capi/capidrv.c	Tue Apr 30 17:10:25 2002
@@ -49,7 +49,7 @@
 
 	struct capidrv_contr *next;
 
-	__u32 contrnr;
+	u32 contrnr;
 	char name[20];
 
 	/*
@@ -62,14 +62,14 @@
 	 * LISTEN state
 	 */
 	int state;
-	__u32 cipmask;
-	__u32 cipmask2;
+	u32 cipmask;
+	u32 cipmask2;
         struct timer_list listentimer;
 
 	/*
 	 * ID of capi message sent
 	 */
-	__u16 msgid;
+	u16 msgid;
 
 	/*
 	 * B-Channels
@@ -77,36 +77,36 @@
 	int nbchan;
 	struct capidrv_bchan {
 		struct capidrv_contr *contr;
-		__u8 msn[ISDN_MSNLEN];
+		u8 msn[ISDN_MSNLEN];
 		int l2;
 		int l3;
-		__u8 num[ISDN_MSNLEN];
-		__u8 mynum[ISDN_MSNLEN];
+		u8 num[ISDN_MSNLEN];
+		u8 mynum[ISDN_MSNLEN];
 		int si1;
 		int si2;
 		int incoming;
 		int disconnecting;
 		struct capidrv_plci {
 			struct capidrv_plci *next;
-			__u32 plci;
-			__u32 ncci;	/* ncci for CONNECT_ACTIVE_IND */
-			__u16 msgid;	/* to identfy CONNECT_CONF */
+			u32 plci;
+			u32 ncci;	/* ncci for CONNECT_ACTIVE_IND */
+			u16 msgid;	/* to identfy CONNECT_CONF */
 			int chan;
 			int state;
 			int leasedline;
 			struct capidrv_ncci {
 				struct capidrv_ncci *next;
 				struct capidrv_plci *plcip;
-				__u32 ncci;
-				__u16 msgid;	/* to identfy CONNECT_B3_CONF */
+				u32 ncci;
+				u16 msgid;	/* to identfy CONNECT_B3_CONF */
 				int chan;
 				int state;
 				int oldstate;
 				/* */
-				__u16 datahandle;
+				u16 datahandle;
 				struct ncci_datahandle_queue {
 				    struct ncci_datahandle_queue *next;
-				    __u16                         datahandle;
+				    u16                         datahandle;
 				    int                           len;
 				} *ackqueue;
 			} *ncci_list;
@@ -117,15 +117,15 @@
 	struct capidrv_plci *plci_list;
 
 	/* for q931 data */
-	__u8  q931_buf[4096];
-	__u8 *q931_read;
-	__u8 *q931_write;
-	__u8 *q931_end;
+	u8  q931_buf[4096];
+	u8 *q931_read;
+	u8 *q931_write;
+	u8 *q931_end;
 };
 
 
 struct capidrv_data {
-	__u16 appid;
+	u16 appid;
 	int ncontr;
 	struct capidrv_contr *contr_list;
 
@@ -149,11 +149,11 @@
 static struct capi_interface *capifuncs;
 
 static void handle_dtrace_data(capidrv_contr *card,
-	int send, int level2, __u8 *data, __u16 len);
+	int send, int level2, u8 *data, u16 len);
 
 /* -------- convert functions ---------------------------------------- */
 
-static inline __u32 b1prot(int l2, int l3)
+static inline u32 b1prot(int l2, int l3)
 {
 	switch (l2) {
 	case ISDN_PROTO_L2_X75I:
@@ -176,7 +176,7 @@
 	}
 }
 
-static inline __u32 b2prot(int l2, int l3)
+static inline u32 b2prot(int l2, int l3)
 {
 	switch (l2) {
 	case ISDN_PROTO_L2_X75I:
@@ -196,7 +196,7 @@
 	}
 }
 
-static inline __u32 b3prot(int l2, int l3)
+static inline u32 b3prot(int l2, int l3)
 {
 	switch (l2) {
 	case ISDN_PROTO_L2_X75I:
@@ -215,7 +215,7 @@
 	}
 }
 
-static _cstruct b1config_async_v110(__u16 rate)
+static _cstruct b1config_async_v110(u16 rate)
 {
 	/* CAPI-Spec "B1 Configuration" */
 	static unsigned char buf[9];
@@ -247,9 +247,9 @@
 	}
 }
 
-static inline __u16 si2cip(__u8 si1, __u8 si2)
+static inline u16 si2cip(u8 si1, u8 si2)
 {
-	static const __u8 cip[17][5] =
+	static const u8 cip[17][5] =
 	{
 	/*  0  1  2  3  4  */
 		{0, 0, 0, 0, 0},	/*0 */
@@ -275,12 +275,12 @@
 	if (si2 > 4)
 		si2 = 0;
 
-	return (__u16) cip[si1][si2];
+	return (u16) cip[si1][si2];
 }
 
-static inline __u8 cip2si1(__u16 cipval)
+static inline u8 cip2si1(u16 cipval)
 {
-	static const __u8 si[32] =
+	static const u8 si[32] =
 	{7, 1, 7, 7, 1, 1, 7, 7,	/*0-7 */
 	 7, 1, 0, 0, 0, 0, 0, 0,	/*8-15 */
 	 1, 2, 4, 10, 9, 9, 15, 7,	/*16-23 */
@@ -291,9 +291,9 @@
 	return si[cipval];
 }
 
-static inline __u8 cip2si2(__u16 cipval)
+static inline u8 cip2si2(u16 cipval)
 {
-	static const __u8 si[32] =
+	static const u8 si[32] =
 	{0, 0, 0, 0, 2, 3, 0, 0,	/*0-7 */
 	 0, 3, 0, 0, 0, 0, 0, 0,	/*8-15 */
 	 1, 2, 0, 0, 9, 0, 0, 0,	/*16-23 */
@@ -320,7 +320,7 @@
 	return p;
 }
 
-static capidrv_contr *findcontrbynumber(__u32 contr)
+static capidrv_contr *findcontrbynumber(u32 contr)
 {
 	unsigned long flags;
 	capidrv_contr *p = global.contr_list;
@@ -357,7 +357,7 @@
 	return plcip;
 }
 
-static capidrv_plci *find_plci_by_plci(capidrv_contr * card, __u32 plci)
+static capidrv_plci *find_plci_by_plci(capidrv_contr * card, u32 plci)
 {
 	capidrv_plci *p;
 	for (p = card->plci_list; p; p = p->next)
@@ -366,7 +366,7 @@
 	return 0;
 }
 
-static capidrv_plci *find_plci_by_msgid(capidrv_contr * card, __u16 msgid)
+static capidrv_plci *find_plci_by_msgid(capidrv_contr * card, u16 msgid)
 {
 	capidrv_plci *p;
 	for (p = card->plci_list; p; p = p->next)
@@ -375,7 +375,7 @@
 	return 0;
 }
 
-static capidrv_plci *find_plci_by_ncci(capidrv_contr * card, __u32 ncci)
+static capidrv_plci *find_plci_by_ncci(capidrv_contr * card, u32 ncci)
 {
 	capidrv_plci *p;
 	for (p = card->plci_list; p; p = p->next)
@@ -406,7 +406,7 @@
 
 static inline capidrv_ncci *new_ncci(capidrv_contr * card,
 				     capidrv_plci * plcip,
-				     __u32 ncci)
+				     u32 ncci)
 {
 	capidrv_ncci *nccip;
 
@@ -430,7 +430,7 @@
 	return nccip;
 }
 
-static inline capidrv_ncci *find_ncci(capidrv_contr * card, __u32 ncci)
+static inline capidrv_ncci *find_ncci(capidrv_contr * card, u32 ncci)
 {
 	capidrv_plci *plcip;
 	capidrv_ncci *p;
@@ -445,7 +445,7 @@
 }
 
 static inline capidrv_ncci *find_ncci_by_msgid(capidrv_contr * card,
-					       __u32 ncci, __u16 msgid)
+					       u32 ncci, u16 msgid)
 {
 	capidrv_plci *plcip;
 	capidrv_ncci *p;
@@ -474,7 +474,7 @@
 }
 
 static int capidrv_add_ack(struct capidrv_ncci *nccip,
-		           __u16 datahandle, int len)
+		           u16 datahandle, int len)
 {
 	struct ncci_datahandle_queue *n, **pp;
 
@@ -492,7 +492,7 @@
 	return 0;
 }
 
-static int capidrv_del_ack(struct capidrv_ncci *nccip, __u16 datahandle)
+static int capidrv_del_ack(struct capidrv_ncci *nccip, u16 datahandle)
 {
 	struct ncci_datahandle_queue **pp, *p;
 	int len;
@@ -798,9 +798,9 @@
 		if (   cmsg->ManuID == 0x214D5641
 		    && cmsg->Class == 0
 		    && cmsg->Function == 1) {
-		   __u8  *data = cmsg->ManuData+3;
-		   __u16  len = cmsg->ManuData[0];
-		   __u16 layer;
+		   u8  *data = cmsg->ManuData+3;
+		   u16  len = cmsg->ManuData[0];
+		   u16 layer;
 		   int direction;
 		   if (len == 255) {
 		      len = (cmsg->ManuData[1] | (cmsg->ManuData[2] << 8));
@@ -1123,10 +1123,10 @@
 				cmd.arg = plcip->chan;
 				sprintf(cmd.parm.num, "%lu",
 					(unsigned long)
-					((__u32) cmsg->InfoElement[1]
-				  | ((__u32) (cmsg->InfoElement[2]) << 8)
-				 | ((__u32) (cmsg->InfoElement[3]) << 16)
-					 | ((__u32) (cmsg->InfoElement[4]) << 24)));
+					((u32) cmsg->InfoElement[1]
+				  | ((u32) (cmsg->InfoElement[2]) << 8)
+				 | ((u32) (cmsg->InfoElement[3]) << 16)
+					 | ((u32) (cmsg->InfoElement[4]) << 24)));
 				card->interface.statcallb(&cmd);
 				break;
 			}
@@ -1373,7 +1373,7 @@
 
 static _cmsg s_cmsg;
 
-static void capidrv_signal(__u16 applid, void *dummy)
+static void capidrv_signal(u16 applid, void *dummy)
 {
 	struct sk_buff *skb = 0;
 
@@ -1415,9 +1415,9 @@
 	} while (0)
 
 static void handle_dtrace_data(capidrv_contr *card,
-			     int send, int level2, __u8 *data, __u16 len)
+			     int send, int level2, u8 *data, u16 len)
 {
-    	__u8 *p, *end;
+    	u8 *p, *end;
     	isdn_ctrl cmd;
 
     	if (!len) {
@@ -1439,7 +1439,7 @@
     	}
 
 	for (p = data, end = data+len; p < end; p++) {
-		__u8 w;
+		u8 w;
 		PUTBYTE_TO_STATUS(card, ' ');
 		w = (*p >> 4) & 0xf;
 		PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w);
@@ -1539,7 +1539,7 @@
 	return 0;
 }
 
-static int FVteln2capi20(char *teln, __u8 AdditionalInfo[1+2+2+31])
+static int FVteln2capi20(char *teln, u8 AdditionalInfo[1+2+2+31])
 {
 	unsigned long bmask;
 	int active;
@@ -1569,7 +1569,7 @@
 	isdn_ctrl cmd;
 	struct capidrv_bchan *bchan;
 	struct capidrv_plci *plcip;
-	__u8 AdditionalInfo[1+2+2+31];
+	u8 AdditionalInfo[1+2+2+31];
         int rc, isleasedline = 0;
 
 	if (c->command == ISDN_CMD_IOCTL)
@@ -1577,8 +1577,8 @@
 
 	switch (c->command) {
 	case ISDN_CMD_DIAL:{
-			__u8 calling[ISDN_MSNLEN + 3];
-			__u8 called[ISDN_MSNLEN + 2];
+			u8 calling[ISDN_MSNLEN + 3];
+			u8 called[ISDN_MSNLEN + 2];
 
 			if (debugmode)
 				printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_DIAL(ch=%ld,\"%s,%d,%d,%s\")\n",
@@ -1870,8 +1870,8 @@
 	capidrv_ncci *nccip;
 	int len = skb->len;
 	size_t msglen;
-	__u16 errcode;
-	__u16 datahandle;
+	u16 errcode;
+	u16 datahandle;
 
 	if (!card) {
 		printk(KERN_ERR "capidrv: if_sendbuf called with invalid driverId %d!\n",
@@ -1891,7 +1891,7 @@
 	datahandle = nccip->datahandle;
 	capi_fill_DATA_B3_REQ(&sendcmsg, global.appid, card->msgid++,
 			      nccip->ncci,	/* adr */
-			      (__u32) skb->data,	/* Data */
+			      (u32) skb->data,	/* Data */
 			      skb->len,		/* DataLength */
 			      datahandle,	/* DataHandle */
 			      0	/* Flags */
@@ -1937,11 +1937,11 @@
 	}
 }
 
-static int if_readstat(__u8 *buf, int len, int user, int id, int channel)
+static int if_readstat(u8 *buf, int len, int user, int id, int channel)
 {
 	capidrv_contr *card = findcontrbydriverid(id);
 	int count;
-	__u8 *p;
+	u8 *p;
 
 	if (!card) {
 		printk(KERN_ERR "capidrv: if_readstat called with invalid driverId %d!\n",
@@ -1963,11 +1963,11 @@
 
 static void enable_dchannel_trace(capidrv_contr *card)
 {
-        __u8 manufacturer[CAPI_MANUFACTURER_LEN];
+        u8 manufacturer[CAPI_MANUFACTURER_LEN];
         capi_version version;
-	__u16 contr = card->contrnr;
-	__u16 errcode;
-	__u16 avmversion[3];
+	u16 contr = card->contrnr;
+	u16 errcode;
+	u16 avmversion[3];
 
         errcode = (*capifuncs->capi_get_manufacturer)(contr, manufacturer);
         if (errcode != CAPI_NOERROR) {
@@ -2037,7 +2037,7 @@
 }
 
 
-static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
+static int capidrv_addcontr(u16 contr, struct capi_profile *profp)
 {
 	capidrv_contr *card;
 	long flags;
@@ -2135,7 +2135,7 @@
 	return 0;
 }
 
-static int capidrv_delcontr(__u16 contr)
+static int capidrv_delcontr(u16 contr)
 {
 	capidrv_contr **pp, *card;
 	unsigned long flags;
@@ -2218,7 +2218,7 @@
 }
 
 
-static void lower_callback(unsigned int cmd, __u32 contr, void *data)
+static void lower_callback(unsigned int cmd, u32 contr, void *data)
 {
 
 	switch (cmd) {
@@ -2303,8 +2303,8 @@
 	capi_profile profile;
 	char rev[32];
 	char *p;
-	__u32 ncontr, contr;
-	__u16 errcode;
+	u32 ncontr, contr;
+	u16 errcode;
 
 	MOD_INC_USE_COUNT;
 
diff -Nru a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c
--- a/drivers/isdn/capi/capifs.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/isdn/capi/capifs.c	Tue Apr 30 17:10:25 2002
@@ -97,18 +97,20 @@
 	off_t nr;
 	char numbuf[32];
 
+	lock_kernel();
+
 	nr = filp->f_pos;
 
 	switch(nr)
 	{
 	case 0:
 		if (filldir(dirent, ".", 1, nr, inode->i_ino, DT_DIR) < 0)
-			return 0;
+			goto out;
 		filp->f_pos = ++nr;
 		/* fall through */
 	case 1:
 		if (filldir(dirent, "..", 2, nr, inode->i_ino, DT_DIR) < 0)
-			return 0;
+			goto out;
 		filp->f_pos = ++nr;
 		/* fall through */
 	default:
@@ -120,13 +122,15 @@
 				if (np->type) *p++ = np->type;
 				sprintf(p, "%u", np->num);
 				if ( filldir(dirent, numbuf, strlen(numbuf), nr, nr, DT_UNKNOWN) < 0 )
-					return 0;
+					goto out;
 			}
 			filp->f_pos = ++nr;
 		}
 		break;
 	}
 
+out:
+	unlock_kernel();
 	return 0;
 }
 
diff -Nru a/drivers/isdn/capi/capiutil.c b/drivers/isdn/capi/capiutil.c
--- a/drivers/isdn/capi/capiutil.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/isdn/capi/capiutil.c	Tue Apr 30 17:10:25 2002
@@ -20,19 +20,15 @@
 #include <linux/config.h>
 #include <linux/isdn/capiutil.h>
 
-MODULE_DESCRIPTION("CAPI4Linux: CAPI message conversion support");
-MODULE_AUTHOR("Carsten Paeth");
-MODULE_LICENSE("GPL");
-
 /* from CAPI2.0 DDK AVM Berlin GmbH */
 
 #ifndef CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
-char *capi_info2str(__u16 reason)
+char *capi_info2str(u16 reason)
 {
     return "..";
 }
 #else
-char *capi_info2str(__u16 reason)
+char *capi_info2str(u16 reason)
 {
     switch (reason) {
 
@@ -422,14 +418,14 @@
 
 /*-------------------------------------------------------*/
 
-#define byteTLcpy(x,y)        *(__u8 *)(x)=*(__u8 *)(y);
-#define wordTLcpy(x,y)        *(__u16 *)(x)=*(__u16 *)(y);
+#define byteTLcpy(x,y)        *(u8 *)(x)=*(u8 *)(y);
+#define wordTLcpy(x,y)        *(u16 *)(x)=*(u16 *)(y);
 #define dwordTLcpy(x,y)       memcpy(x,y,4);
 #define structTLcpy(x,y,l)    memcpy (x,y,l)
 #define structTLcpyovl(x,y,l) memmove (x,y,l)
 
-#define byteTRcpy(x,y)        *(__u8 *)(y)=*(__u8 *)(x);
-#define wordTRcpy(x,y)        *(__u16 *)(y)=*(__u16 *)(x);
+#define byteTRcpy(x,y)        *(u8 *)(y)=*(u8 *)(x);
+#define wordTRcpy(x,y)        *(u16 *)(y)=*(u16 *)(x);
 #define dwordTRcpy(x,y)       memcpy(y,x,4);
 #define structTRcpy(x,y,l)    memcpy (y,x,l)
 #define structTRcpyovl(x,y,l) memmove (y,x,l)
@@ -449,7 +445,7 @@
 
 /*-------------------------------------------------------*/
 #define TYP (cdef[cmsg->par[cmsg->p]].typ)
-#define OFF (((__u8 *)cmsg)+cdef[cmsg->par[cmsg->p]].off)
+#define OFF (((u8 *)cmsg)+cdef[cmsg->par[cmsg->p]].off)
 
 static void jumpcstruct(_cmsg * cmsg)
 {
@@ -486,7 +482,7 @@
 			cmsg->l += 4;
 			break;
 		case _CSTRUCT:
-			if (*(__u8 **) OFF == 0) {
+			if (*(u8 **) OFF == 0) {
 				*(cmsg->m + cmsg->l) = '\0';
 				cmsg->l++;
 			} else if (**(_cstruct *) OFF != 0xff) {
@@ -494,8 +490,8 @@
 				cmsg->l += 1 + **(_cstruct *) OFF;
 			} else {
 				_cstruct s = *(_cstruct *) OFF;
-				structTLcpy(cmsg->m + cmsg->l, s, 3 + *(__u16 *) (s + 1));
-				cmsg->l += 3 + *(__u16 *) (s + 1);
+				structTLcpy(cmsg->m + cmsg->l, s, 3 + *(u16 *) (s + 1));
+				cmsg->l += 3 + *(u16 *) (s + 1);
 			}
 			break;
 		case _CMSTRUCT:
@@ -514,7 +510,7 @@
 				pars_2_message(cmsg);
 				_ls = cmsg->l - _l - 1;
 				if (_ls < 255)
-					(cmsg->m + _l)[0] = (__u8) _ls;
+					(cmsg->m + _l)[0] = (u8) _ls;
 				else {
 					structTLcpyovl(cmsg->m + _l + 3, cmsg->m + _l + 1, _ls);
 					(cmsg->m + _l)[0] = 0xff;
@@ -527,7 +523,7 @@
 }
 
 /*-------------------------------------------------------*/
-unsigned capi_cmsg2message(_cmsg * cmsg, __u8 * msg)
+unsigned capi_cmsg2message(_cmsg * cmsg, u8 * msg)
 {
 	cmsg->m = msg;
 	cmsg->l = 8;
@@ -564,12 +560,12 @@
 			cmsg->l += 4;
 			break;
 		case _CSTRUCT:
-			*(__u8 **) OFF = cmsg->m + cmsg->l;
+			*(u8 **) OFF = cmsg->m + cmsg->l;
 
 			if (cmsg->m[cmsg->l] != 0xff)
 				cmsg->l += 1 + cmsg->m[cmsg->l];
 			else
-				cmsg->l += 3 + *(__u16 *) (cmsg->m + cmsg->l + 1);
+				cmsg->l += 3 + *(u16 *) (cmsg->m + cmsg->l + 1);
 			break;
 		case _CMSTRUCT:
 /*----- Metastruktur 0 -----*/
@@ -590,7 +586,7 @@
 }
 
 /*-------------------------------------------------------*/
-unsigned capi_message2cmsg(_cmsg * cmsg, __u8 * msg)
+unsigned capi_message2cmsg(_cmsg * cmsg, u8 * msg)
 {
 	memset(cmsg, 0, sizeof(_cmsg));
 	cmsg->m = msg;
@@ -610,9 +606,9 @@
 }
 
 /*-------------------------------------------------------*/
-unsigned capi_cmsg_header(_cmsg * cmsg, __u16 _ApplId,
-			  __u8 _Command, __u8 _Subcommand,
-			  __u16 _Messagenumber, __u32 _Controller)
+unsigned capi_cmsg_header(_cmsg * cmsg, u16 _ApplId,
+			  u8 _Command, u8 _Subcommand,
+			  u16 _Messagenumber, u32 _Controller)
 {
 	memset(cmsg, 0, sizeof(_cmsg));
 	cmsg->ApplId = _ApplId;
@@ -708,7 +704,7 @@
 	"MANUFACTURER_RESP"
 };
 
-char *capi_cmd2str(__u8 cmd, __u8 subcmd)
+char *capi_cmd2str(u8 cmd, u8 subcmd)
 {
 	return mnames[command_2_index(cmd, subcmd)];
 }
@@ -785,7 +781,7 @@
 	p += strlen(p);
 }
 
-static void printstructlen(__u8 * m, unsigned len)
+static void printstructlen(u8 * m, unsigned len)
 {
 	unsigned hex = 0;
 	for (; len; len--, m++)
@@ -805,14 +801,14 @@
 		bufprint(">");
 }
 
-static void printstruct(__u8 * m)
+static void printstruct(u8 * m)
 {
 	unsigned len;
 	if (m[0] != 0xff) {
 		len = m[0];
 		m += 1;
 	} else {
-		len = ((__u16 *) (m + 1))[0];
+		len = ((u16 *) (m + 1))[0];
 		m += 3;
 	}
 	printstructlen(m, len);
@@ -833,15 +829,15 @@
 
 		switch (TYP) {
 		case _CBYTE:
-			bufprint("%-*s = 0x%x\n", slen, NAME, *(__u8 *) (cmsg->m + cmsg->l));
+			bufprint("%-*s = 0x%x\n", slen, NAME, *(u8 *) (cmsg->m + cmsg->l));
 			cmsg->l++;
 			break;
 		case _CWORD:
-			bufprint("%-*s = 0x%x\n", slen, NAME, *(__u16 *) (cmsg->m + cmsg->l));
+			bufprint("%-*s = 0x%x\n", slen, NAME, *(u16 *) (cmsg->m + cmsg->l));
 			cmsg->l += 2;
 			break;
 		case _CDWORD:
-			bufprint("%-*s = 0x%lx\n", slen, NAME, *(__u32 *) (cmsg->m + cmsg->l));
+			bufprint("%-*s = 0x%lx\n", slen, NAME, *(u32 *) (cmsg->m + cmsg->l));
 			cmsg->l += 4;
 			break;
 		case _CSTRUCT:
@@ -854,7 +850,7 @@
 			if (cmsg->m[cmsg->l] != 0xff)
 				cmsg->l += 1 + cmsg->m[cmsg->l];
 			else
-				cmsg->l += 3 + *(__u16 *) (cmsg->m + cmsg->l + 1);
+				cmsg->l += 3 + *(u16 *) (cmsg->m + cmsg->l + 1);
 
 			break;
 
@@ -877,7 +873,7 @@
 	}
 }
 /*-------------------------------------------------------*/
-char *capi_message2str(__u8 * msg)
+char *capi_message2str(u8 * msg)
 {
 
 	_cmsg cmsg;
@@ -909,9 +905,9 @@
 	cmsg->p = 0;
 	bufprint("%s ID=%03d #0x%04x LEN=%04d\n",
 		 mnames[command_2_index(cmsg->Command, cmsg->Subcommand)],
-		 ((__u16 *) cmsg->m)[1],
-		 ((__u16 *) cmsg->m)[3],
-		 ((__u16 *) cmsg->m)[0]);
+		 ((u16 *) cmsg->m)[1],
+		 ((u16 *) cmsg->m)[3],
+		 ((u16 *) cmsg->m)[0]);
 	protocol_message_2_pars(cmsg, 1);
 	return buf;
 }
@@ -923,15 +919,3 @@
 EXPORT_SYMBOL(capi_cmsg2str);
 EXPORT_SYMBOL(capi_message2str);
 EXPORT_SYMBOL(capi_info2str);
-
-static int __init capiutil_init(void)
-{ 
-	return 0; 
-}
-
-static void __exit capiutil_exit(void)
-{
-}
-
-module_init(capiutil_init);
-module_exit(capiutil_exit);
diff -Nru a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c
--- a/drivers/isdn/capi/kcapi.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/isdn/capi/kcapi.c	Tue Apr 30 17:10:25 2002
@@ -54,14 +54,14 @@
 
 struct msgidqueue {
 	struct msgidqueue *next;
-	__u16 msgid;
+	u16 msgid;
 };
 
 struct capi_ncci {
 	struct capi_ncci *next;
-	__u16 applid;
-	__u32 ncci;
-	__u32 winsize;
+	u16 applid;
+	u32 ncci;
+	u32 winsize;
 	int   nmsg;
 	struct msgidqueue *msgidqueue;
 	struct msgidqueue *msgidlast;
@@ -70,11 +70,11 @@
 };
 
 struct capi_appl {
-	__u16 applid;
+	u16 applid;
 	capi_register_params rparam;
 	int releasing;
 	void *param;
-	void (*signal) (__u16 applid, void *param);
+	void (*signal) (u16 applid, void *param);
 	struct sk_buff_head recv_queue;
 	int nncci;
 	struct capi_ncci *nccilist;
@@ -88,9 +88,9 @@
 struct capi_notifier {
 	struct capi_notifier *next;
 	unsigned int cmd;
-	__u32 controller;
-	__u16 applid;
-	__u32 ncci;
+	u32 controller;
+	u16 applid;
+	u32 ncci;
 };
 
 /* ------------------------------------------------------------- */
@@ -136,7 +136,7 @@
 	}
 }
 
-static inline int capi_cmd_valid(__u8 cmd)
+static inline int capi_cmd_valid(u8 cmd)
 {
 	switch (cmd) {
 	case CAPI_ALERT:
@@ -159,7 +159,7 @@
 	return 0;
 }
 
-static inline int capi_subcmd_valid(__u8 subcmd)
+static inline int capi_subcmd_valid(u8 subcmd)
 {
 	switch (subcmd) {
 	case CAPI_REQ:
@@ -511,8 +511,8 @@
 	return np;
 }
 
-static int notify_push(unsigned int cmd, __u32 controller,
-				__u16 applid, __u32 ncci)
+static int notify_push(unsigned int cmd, u32 controller,
+				u16 applid, u32 ncci)
 {
 	struct capi_notifier *np;
 
@@ -541,7 +541,7 @@
 
 /* -------- KCI_CONTRUP --------------------------------------- */
 
-static void notify_up(__u32 contr)
+static void notify_up(u32 contr)
 {
 	struct capi_interface_user *p;
 
@@ -556,7 +556,7 @@
 
 /* -------- KCI_CONTRDOWN ------------------------------------- */
 
-static void notify_down(__u32 contr)
+static void notify_down(u32 contr)
 {
 	struct capi_interface_user *p;
         printk(KERN_NOTICE "kcapi: notify down contr %d\n", contr);
@@ -570,7 +570,7 @@
 
 /* -------- KCI_NCCIUP ---------------------------------------- */
 
-static void notify_ncciup(__u32 contr, __u16 applid, __u32 ncci)
+static void notify_ncciup(u32 contr, u16 applid, u32 ncci)
 {
 	struct capi_interface_user *p;
 	struct capi_ncciinfo n;
@@ -587,7 +587,7 @@
 
 /* -------- KCI_NCCIDOWN -------------------------------------- */
 
-static void notify_nccidown(__u32 contr, __u16 applid, __u32 ncci)
+static void notify_nccidown(u32 contr, u16 applid, u32 ncci)
 {
 	struct capi_interface_user *p;
 	struct capi_ncciinfo n;
@@ -650,7 +650,7 @@
 	}
 }
 
-static inline int mq_enqueue(struct capi_ncci * np, __u16 msgid)
+static inline int mq_enqueue(struct capi_ncci * np, u16 msgid)
 {
 	struct msgidqueue *mq;
 	if ((mq = np->msgidfree) == 0)
@@ -667,7 +667,7 @@
 	return 1;
 }
 
-static inline int mq_dequeue(struct capi_ncci * np, __u16 msgid)
+static inline int mq_dequeue(struct capi_ncci * np, u16 msgid)
 {
 	struct msgidqueue **pp;
 	for (pp = &np->msgidqueue; *pp; pp = &(*pp)->next) {
@@ -685,11 +685,11 @@
 	return 0;
 }
 
-static void controllercb_appl_registered(struct capi_ctr * card, __u16 appl)
+static void controllercb_appl_registered(struct capi_ctr * card, u16 appl)
 {
 }
 
-static void controllercb_appl_released(struct capi_ctr * card, __u16 appl)
+static void controllercb_appl_released(struct capi_ctr * card, u16 appl)
 {
 	struct capi_ncci **pp, **nextpp;
 	for (pp = &APPL(appl)->nccilist; *pp; pp = nextpp) {
@@ -716,7 +716,7 @@
  */
 
 static void controllercb_new_ncci(struct capi_ctr * card,
-					__u16 appl, __u32 ncci, __u32 winsize)
+					u16 appl, u32 ncci, u32 winsize)
 {
 	struct capi_ncci *np;
 	if (!VALID_APPLID(appl)) {
@@ -745,7 +745,7 @@
 }
 
 static void controllercb_free_ncci(struct capi_ctr * card,
-				__u16 appl, __u32 ncci)
+				u16 appl, u32 ncci)
 {
 	struct capi_ncci **pp;
 	if (!VALID_APPLID(appl)) {
@@ -767,7 +767,7 @@
 }
 
 
-static struct capi_ncci *find_ncci(struct capi_appl * app, __u32 ncci)
+static struct capi_ncci *find_ncci(struct capi_appl * app, u32 ncci)
 {
 	struct capi_ncci *np;
 	for (np = app->nccilist; np; np = np->next) {
@@ -784,7 +784,7 @@
 	struct sk_buff *skb;
 
 	while ((skb = skb_dequeue(&recv_queue)) != 0) {
-		__u16 appl = CAPIMSG_APPID(skb->data);
+		u16 appl = CAPIMSG_APPID(skb->data);
 		struct capi_ncci *np;
 		if (!VALID_APPLID(appl)) {
 			printk(KERN_ERR "kcapi: recv_handler: applid %d ? (%s)\n",
@@ -817,10 +817,10 @@
 }
 
 static void controllercb_handle_capimsg(struct capi_ctr * card,
-				__u16 appl, struct sk_buff *skb)
+				u16 appl, struct sk_buff *skb)
 {
 	int showctl = 0;
-	__u8 cmd, subcmd;
+	u8 cmd, subcmd;
 
 	if (card->cardstate != CARD_RUNNING) {
 		printk(KERN_INFO "kcapi: controller %d not active, got: %s",
@@ -862,7 +862,7 @@
 
 static void controllercb_ready(struct capi_ctr * card)
 {
-	__u16 appl;
+	u16 appl;
 
 	card->cardstate = CARD_RUNNING;
 
@@ -880,7 +880,7 @@
 
 static void controllercb_reseted(struct capi_ctr * card)
 {
-	__u16 appl;
+	u16 appl;
 
         if (card->cardstate == CARD_FREE)
 		return;
@@ -1088,7 +1088,7 @@
 /* -------- CAPI2.0 Interface ---------------------------------- */
 /* ------------------------------------------------------------- */
 
-static __u16 capi_isinstalled(void)
+static u16 capi_isinstalled(void)
 {
 	int i;
 	for (i = 0; i < CAPI_MAXCONTR; i++) {
@@ -1098,7 +1098,7 @@
 	return CAPI_REGNOTINSTALLED;
 }
 
-static __u16 capi_register(capi_register_params * rparam, __u16 * applidp)
+static u16 capi_register(capi_register_params * rparam, u16 * applidp)
 {
 	int appl;
 	int i;
@@ -1131,7 +1131,7 @@
 	return CAPI_NOERROR;
 }
 
-static __u16 capi_release(__u16 applid)
+static u16 capi_release(u16 applid)
 {
 	int i;
 
@@ -1154,12 +1154,12 @@
 	return CAPI_NOERROR;
 }
 
-static __u16 capi_put_message(__u16 applid, struct sk_buff *skb)
+static u16 capi_put_message(u16 applid, struct sk_buff *skb)
 {
 	struct capi_ncci *np;
-	__u32 contr;
+	u32 contr;
 	int showctl = 0;
-	__u8 cmd, subcmd;
+	u8 cmd, subcmd;
 
 	if (ncards == 0)
 		return CAPI_REGNOTINSTALLED;
@@ -1212,7 +1212,7 @@
 	return CAPI_NOERROR;
 }
 
-static __u16 capi_get_message(__u16 applid, struct sk_buff **msgp)
+static u16 capi_get_message(u16 applid, struct sk_buff **msgp)
 {
 	struct sk_buff *skb;
 
@@ -1224,8 +1224,8 @@
 	return CAPI_NOERROR;
 }
 
-static __u16 capi_set_signal(__u16 applid,
-			     void (*signal) (__u16 applid, void *param),
+static u16 capi_set_signal(u16 applid,
+			     void (*signal) (u16 applid, void *param),
 			     void *param)
 {
 	if (!VALID_APPLID(applid))
@@ -1235,7 +1235,7 @@
 	return CAPI_NOERROR;
 }
 
-static __u16 capi_get_manufacturer(__u32 contr, __u8 buf[CAPI_MANUFACTURER_LEN])
+static u16 capi_get_manufacturer(u32 contr, u8 buf[CAPI_MANUFACTURER_LEN])
 {
 	if (contr == 0) {
 		strncpy(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN);
@@ -1248,7 +1248,7 @@
 	return CAPI_NOERROR;
 }
 
-static __u16 capi_get_version(__u32 contr, struct capi_version *verp)
+static u16 capi_get_version(u32 contr, struct capi_version *verp)
 {
 	if (contr == 0) {
 		*verp = driver_version;
@@ -1261,7 +1261,7 @@
 	return CAPI_NOERROR;
 }
 
-static __u16 capi_get_serial(__u32 contr, __u8 serial[CAPI_SERIAL_LEN])
+static u16 capi_get_serial(u32 contr, u8 serial[CAPI_SERIAL_LEN])
 {
 	if (contr == 0) {
 		strncpy(serial, driver_serial, CAPI_SERIAL_LEN);
@@ -1274,7 +1274,7 @@
 	return CAPI_NOERROR;
 }
 
-static __u16 capi_get_profile(__u32 contr, struct capi_profile *profp)
+static u16 capi_get_profile(u32 contr, struct capi_profile *profp)
 {
 	if (contr == 0) {
 		profp->ncontroller = ncards;
diff -Nru a/drivers/isdn/hardware/avm/avmcard.h b/drivers/isdn/hardware/avm/avmcard.h
--- a/drivers/isdn/hardware/avm/avmcard.h	Tue Apr 30 17:10:25 2002
+++ b/drivers/isdn/hardware/avm/avmcard.h	Tue Apr 30 17:10:25 2002
@@ -41,12 +41,12 @@
 
 typedef struct avmcard_dmabuf {
     long        size;
-    __u8       *dmabuf;
+    u8       *dmabuf;
     dma_addr_t  dmaaddr;
 } avmcard_dmabuf;
 
 typedef struct avmcard_dmainfo {
-	__u32                recvlen;
+	u32                recvlen;
         avmcard_dmabuf       recvbuf;
 
         avmcard_dmabuf       sendbuf;
@@ -71,7 +71,7 @@
 	int interrupt;
 
 	void *mbase;
-	volatile __u32 csr;
+	volatile u32 csr;
 	avmcard_dmainfo *dma;
 
 	struct avmctrl_info {
@@ -542,9 +542,9 @@
 
 int b1_load_firmware(struct capi_ctr *ctrl, capiloaddata *data);
 void b1_reset_ctr(struct capi_ctr *ctrl);
-void b1_register_appl(struct capi_ctr *ctrl, __u16 appl,
+void b1_register_appl(struct capi_ctr *ctrl, u16 appl,
 				capi_register_params *rp);
-void b1_release_appl(struct capi_ctr *ctrl, __u16 appl);
+void b1_release_appl(struct capi_ctr *ctrl, u16 appl);
 void b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
 void b1_parse_version(avmctrl_info *card);
 void b1_handle_interrupt(avmcard * card);
@@ -567,9 +567,9 @@
 void b1dma_reset_ctr(struct capi_ctr *ctrl);
 void b1dma_remove_ctr(struct capi_ctr *ctrl);
 void b1dma_register_appl(struct capi_ctr *ctrl,
-				__u16 appl,
+				u16 appl,
 				capi_register_params *rp);
-void b1dma_release_appl(struct capi_ctr *ctrl, __u16 appl);
+void b1dma_release_appl(struct capi_ctr *ctrl, u16 appl);
 void b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
 int b1dmactl_read_proc(char *page, char **start, off_t off,
         		int count, int *eof, struct capi_ctr *ctrl);
diff -Nru a/drivers/isdn/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c
--- a/drivers/isdn/hardware/avm/b1.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/isdn/hardware/avm/b1.c	Tue Apr 30 17:10:25 2002
@@ -297,7 +297,7 @@
 }
 
 void b1_register_appl(struct capi_ctr *ctrl,
-				__u16 appl,
+				u16 appl,
 				capi_register_params *rp)
 {
 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
@@ -323,7 +323,7 @@
 	ctrl->appl_registered(ctrl, appl);
 }
 
-void b1_release_appl(struct capi_ctr *ctrl, __u16 appl)
+void b1_release_appl(struct capi_ctr *ctrl, u16 appl)
 {
 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
 	avmcard *card = cinfo->card;
@@ -343,14 +343,14 @@
 	avmcard *card = cinfo->card;
 	unsigned int port = card->port;
 	unsigned long flags;
-	__u16 len = CAPIMSG_LEN(skb->data);
-	__u8 cmd = CAPIMSG_COMMAND(skb->data);
-	__u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
+	u16 len = CAPIMSG_LEN(skb->data);
+	u8 cmd = CAPIMSG_COMMAND(skb->data);
+	u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
 
 	save_flags(flags);
 	cli();
 	if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
-		__u16 dlen = CAPIMSG_DATALEN(skb->data);
+		u16 dlen = CAPIMSG_DATALEN(skb->data);
 		b1_put_byte(port, SEND_DATA_B3_REQ);
 		b1_put_slice(port, skb->data, len);
 		b1_put_slice(port, skb->data + len, dlen);
@@ -369,8 +369,8 @@
 	struct capi_ctr *ctrl = cinfo->capi_ctrl;
 	avmcard *card = cinfo->card;
 	capi_profile *profp;
-	__u8 *dversion;
-	__u8 flag;
+	u8 *dversion;
+	u8 flag;
 	int i, j;
 
 	for (j = 0; j < AVM_MAXVERSION; j++)
@@ -394,7 +394,7 @@
 
 	profp = &ctrl->profile;
 
-	flag = ((__u8 *)(profp->manu))[1];
+	flag = ((u8 *)(profp->manu))[1];
 	switch (flag) {
 	case 0: if (cinfo->version[VER_CARDTYPE])
 	           strcpy(cinfo->cardname, cinfo->version[VER_CARDTYPE]);
@@ -410,7 +410,7 @@
         printk(KERN_NOTICE "%s: card %d \"%s\" ready.\n",
 				card->name, ctrl->cnr, cinfo->cardname);
 
-        flag = ((__u8 *)(profp->manu))[3];
+        flag = ((u8 *)(profp->manu))[3];
         if (flag)
 		printk(KERN_NOTICE "%s: card %d Protocol:%s%s%s%s%s%s%s\n",
 			card->name,
@@ -424,7 +424,7 @@
 			(flag & 0x40) ? " 1TR6" : ""
 			);
 
-        flag = ((__u8 *)(profp->manu))[5];
+        flag = ((u8 *)(profp->manu))[5];
 	if (flag)
 		printk(KERN_NOTICE "%s: card %d Linetype:%s%s%s%s\n",
 			card->name,
@@ -574,7 +574,7 @@
 {
 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
 	avmcard *card = cinfo->card;
-	__u8 flag;
+	u8 flag;
 	int len = 0;
 	char *s;
 
@@ -604,7 +604,7 @@
 	   len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
 
 	if (card->cardtype != avm_m1) {
-        	flag = ((__u8 *)(ctrl->profile.manu))[3];
+        	flag = ((u8 *)(ctrl->profile.manu))[3];
         	if (flag)
 			len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n",
 			"protocol",
@@ -618,7 +618,7 @@
 			);
 	}
 	if (card->cardtype != avm_m1) {
-        	flag = ((__u8 *)(ctrl->profile.manu))[5];
+        	flag = ((u8 *)(ctrl->profile.manu))[5];
 		if (flag)
 			len += sprintf(page+len, "%-16s%s%s%s%s\n",
 			"linetype",
diff -Nru a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c
--- a/drivers/isdn/hardware/avm/b1dma.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/isdn/hardware/avm/b1dma.c	Tue Apr 30 17:10:25 2002
@@ -130,41 +130,41 @@
 	return 0;
 }
 
-static int WriteReg(avmcard *card, __u32 reg, __u8 val)
+static int WriteReg(avmcard *card, u32 reg, u8 val)
 {
-	__u8 cmd = 0x00;
+	u8 cmd = 0x00;
 	if (   b1dma_tolink(card, &cmd, 1) == 0
 	    && b1dma_tolink(card, &reg, 4) == 0) {
-		__u32 tmp = val;
+		u32 tmp = val;
 		return b1dma_tolink(card, &tmp, 4);
 	}
 	return -1;
 }
 
-static __u8 ReadReg(avmcard *card, __u32 reg)
+static u8 ReadReg(avmcard *card, u32 reg)
 {
-	__u8 cmd = 0x01;
+	u8 cmd = 0x01;
 	if (   b1dma_tolink(card, &cmd, 1) == 0
 	    && b1dma_tolink(card, &reg, 4) == 0) {
-		__u32 tmp;
+		u32 tmp;
 		if (b1dma_fromlink(card, &tmp, 4) == 0)
-			return (__u8)tmp;
+			return (u8)tmp;
 	}
 	return 0xff;
 }
 
 /* ------------------------------------------------------------- */
 
-static inline void _put_byte(void **pp, __u8 val)
+static inline void _put_byte(void **pp, u8 val)
 {
-	__u8 *s = *pp;
+	u8 *s = *pp;
 	*s++ = val;
 	*pp = s;
 }
 
-static inline void _put_word(void **pp, __u32 val)
+static inline void _put_word(void **pp, u32 val)
 {
-	__u8 *s = *pp;
+	u8 *s = *pp;
 	*s++ = val & 0xff;
 	*s++ = (val >> 8) & 0xff;
 	*s++ = (val >> 16) & 0xff;
@@ -180,19 +180,19 @@
 		_put_byte(pp, *dp++);
 }
 
-static inline __u8 _get_byte(void **pp)
+static inline u8 _get_byte(void **pp)
 {
-	__u8 *s = *pp;
-	__u8 val;
+	u8 *s = *pp;
+	u8 val;
 	val = *s++;
 	*pp = s;
 	return val;
 }
 
-static inline __u32 _get_word(void **pp)
+static inline u32 _get_word(void **pp)
 {
-	__u8 *s = *pp;
-	__u32 val;
+	u8 *s = *pp;
+	u32 val;
 	val = *s++;
 	val |= (*s++ << 8);
 	val |= (*s++ << 16);
@@ -201,7 +201,7 @@
 	return val;
 }
 
-static inline __u32 _get_slice(void **pp, unsigned char *dp)
+static inline u32 _get_slice(void **pp, unsigned char *dp)
 {
 	unsigned int len, i;
 
@@ -357,9 +357,9 @@
 	avmcard_dmainfo *dma = card->dma;
 	unsigned long flags;
 	struct sk_buff *skb;
-	__u8 cmd, subcmd;
-	__u16 len;
-	__u32 txlen;
+	u8 cmd, subcmd;
+	u16 len;
+	u32 txlen;
 	int inint;
 	void *p;
 	
@@ -391,7 +391,7 @@
 		p = dma->sendbuf.dmabuf;
 
 		if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
-			__u16 dlen = CAPIMSG_DATALEN(skb->data);
+			u16 dlen = CAPIMSG_DATALEN(skb->data);
 			_put_byte(&p, SEND_DATA_B3_REQ);
 			_put_slice(&p, skb->data, len);
 			_put_slice(&p, skb->data + len, dlen);
@@ -399,7 +399,7 @@
 			_put_byte(&p, SEND_MESSAGE);
 			_put_slice(&p, skb->data, len);
 		}
-		txlen = (__u8 *)p - (__u8 *)dma->sendbuf.dmabuf;
+		txlen = (u8 *)p - (u8 *)dma->sendbuf.dmabuf;
 #ifdef CONFIG_B1DMA_DEBUG
 		printk(KERN_DEBUG "tx(%d): put msg len=%d\n",
 				inint, txlen);
@@ -447,7 +447,7 @@
 	_put_byte(&p, 0);
 	_put_byte(&p, 0);
 	_put_byte(&p, SEND_POLLACK);
-	skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+	skb_put(skb, (u8 *)p - (u8 *)skb->data);
 
 	skb_queue_tail(&card->dma->send_queue, skb);
 	b1dma_dispatch_tx(card);
@@ -462,8 +462,8 @@
 	struct capi_ctr *ctrl = cinfo->capi_ctrl;
 	struct sk_buff *skb;
 	void *p = dma->recvbuf.dmabuf+4;
-	__u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;
-	__u8 b1cmd =  _get_byte(&p);
+	u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;
+	u8 b1cmd =  _get_byte(&p);
 
 #ifdef CONFIG_B1DMA_DEBUG
 	printk(KERN_DEBUG "rx: 0x%x %lu\n", b1cmd, (unsigned long)dma->recvlen);
@@ -585,8 +585,8 @@
 
 static void b1dma_handle_interrupt(avmcard *card)
 {
-	__u32 status = b1dmainmeml(card->mbase+AMCC_INTCSR);
-	__u32 newcsr;
+	u32 status = b1dmainmeml(card->mbase+AMCC_INTCSR);
+	u32 newcsr;
 
 	if ((status & ANY_S5933_INT) == 0) 
 		return;
@@ -598,9 +598,9 @@
 
 	if ((status & RX_TC_INT) != 0) {
 		struct avmcard_dmainfo *dma = card->dma;
-		__u32 rxlen;
+		u32 rxlen;
 	   	if (card->dma->recvlen == 0) {
-			dma->recvlen = *((__u32 *)dma->recvbuf.dmabuf);
+			dma->recvlen = *((u32 *)dma->recvbuf.dmabuf);
 			rxlen = (dma->recvlen + 3) & ~3;
 			b1dmaoutmeml(card->mbase+AMCC_RXPTR,
 					dma->recvbuf.dmaaddr+4);
@@ -695,7 +695,7 @@
 	_put_word(&p, CAPI_MAXAPPL);
 	_put_word(&p, AVM_NCCI_PER_CHANNEL*30);
 	_put_word(&p, card->cardnr - 1);
-	skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+	skb_put(skb, (u8 *)p - (u8 *)skb->data);
 
 	skb_queue_tail(&card->dma->send_queue, skb);
 	b1dma_dispatch_tx(card);
@@ -772,7 +772,7 @@
 
 
 void b1dma_register_appl(struct capi_ctr *ctrl,
-				__u16 appl,
+				u16 appl,
 				capi_register_params *rp)
 {
 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
@@ -801,7 +801,7 @@
 	_put_word(&p, nconn);
 	_put_word(&p, rp->datablkcnt);
 	_put_word(&p, rp->datablklen);
-	skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+	skb_put(skb, (u8 *)p - (u8 *)skb->data);
 
 	skb_queue_tail(&card->dma->send_queue, skb);
 	b1dma_dispatch_tx(card);
@@ -811,7 +811,7 @@
 
 /* ------------------------------------------------------------- */
 
-void b1dma_release_appl(struct capi_ctr *ctrl, __u16 appl)
+void b1dma_release_appl(struct capi_ctr *ctrl, u16 appl)
 {
 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
 	avmcard *card = cinfo->card;
@@ -830,7 +830,7 @@
 	_put_byte(&p, SEND_RELEASE);
 	_put_word(&p, appl);
 
-	skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+	skb_put(skb, (u8 *)p - (u8 *)skb->data);
 	skb_queue_tail(&card->dma->send_queue, skb);
 	b1dma_dispatch_tx(card);
 }
@@ -853,10 +853,10 @@
 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
 	avmcard *card = cinfo->card;
 	unsigned long flags;
-	__u8 flag;
+	u8 flag;
 	int len = 0;
 	char *s;
-	__u32 txoff, txlen, rxoff, rxlen, csr;
+	u32 txoff, txlen, rxoff, rxlen, csr;
 
 	len += sprintf(page+len, "%-16s %s\n", "name", card->name);
 	len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port);
@@ -883,7 +883,7 @@
 	   len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
 
 	if (card->cardtype != avm_m1) {
-        	flag = ((__u8 *)(ctrl->profile.manu))[3];
+        	flag = ((u8 *)(ctrl->profile.manu))[3];
         	if (flag)
 			len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n",
 			"protocol",
@@ -897,7 +897,7 @@
 			);
 	}
 	if (card->cardtype != avm_m1) {
-        	flag = ((__u8 *)(ctrl->profile.manu))[5];
+        	flag = ((u8 *)(ctrl->profile.manu))[5];
 		if (flag)
 			len += sprintf(page+len, "%-16s%s%s%s%s\n",
 			"linetype",
diff -Nru a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c
--- a/drivers/isdn/hardware/avm/c4.c	Tue Apr 30 17:10:23 2002
+++ b/drivers/isdn/hardware/avm/c4.c	Tue Apr 30 17:10:23 2002
@@ -193,14 +193,14 @@
 
 static int c4_load_t4file(avmcard *card, capiloaddatapart * t4file)
 {
-	__u32 val;
+	u32 val;
 	unsigned char *dp;
 	int left, retval;
-	__u32 loadoff = 0;
+	u32 loadoff = 0;
 
 	dp = t4file->data;
 	left = t4file->len;
-	while (left >= sizeof(__u32)) {
+	while (left >= sizeof(u32)) {
 	        if (t4file->user) {
 			retval = copy_from_user(&val, dp, sizeof(val));
 			if (retval)
@@ -213,9 +213,9 @@
 					card->name);
 			return -EIO;
 		}
-		left -= sizeof(__u32);
-		dp += sizeof(__u32);
-		loadoff += sizeof(__u32);
+		left -= sizeof(u32);
+		dp += sizeof(u32);
+		loadoff += sizeof(u32);
 	}
 	if (left) {
 		val = 0;
@@ -237,16 +237,16 @@
 
 /* ------------------------------------------------------------- */
 
-static inline void _put_byte(void **pp, __u8 val)
+static inline void _put_byte(void **pp, u8 val)
 {
-	__u8 *s = *pp;
+	u8 *s = *pp;
 	*s++ = val;
 	*pp = s;
 }
 
-static inline void _put_word(void **pp, __u32 val)
+static inline void _put_word(void **pp, u32 val)
 {
-	__u8 *s = *pp;
+	u8 *s = *pp;
 	*s++ = val & 0xff;
 	*s++ = (val >> 8) & 0xff;
 	*s++ = (val >> 16) & 0xff;
@@ -262,19 +262,19 @@
 		_put_byte(pp, *dp++);
 }
 
-static inline __u8 _get_byte(void **pp)
+static inline u8 _get_byte(void **pp)
 {
-	__u8 *s = *pp;
-	__u8 val;
+	u8 *s = *pp;
+	u8 val;
 	val = *s++;
 	*pp = s;
 	return val;
 }
 
-static inline __u32 _get_word(void **pp)
+static inline u32 _get_word(void **pp)
 {
-	__u8 *s = *pp;
-	__u32 val;
+	u8 *s = *pp;
+	u32 val;
 	val = *s++;
 	val |= (*s++ << 8);
 	val |= (*s++ << 16);
@@ -283,7 +283,7 @@
 	return val;
 }
 
-static inline __u32 _get_slice(void **pp, unsigned char *dp)
+static inline u32 _get_slice(void **pp, unsigned char *dp)
 {
 	unsigned int len, i;
 
@@ -411,9 +411,9 @@
 	avmcard_dmainfo *dma = card->dma;
 	unsigned long flags;
 	struct sk_buff *skb;
-	__u8 cmd, subcmd;
-	__u16 len;
-	__u32 txlen;
+	u8 cmd, subcmd;
+	u16 len;
+	u32 txlen;
 	void *p;
 	
 	save_flags(flags);
@@ -442,7 +442,7 @@
 		p = dma->sendbuf.dmabuf;
 
 		if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
-			__u16 dlen = CAPIMSG_DATALEN(skb->data);
+			u16 dlen = CAPIMSG_DATALEN(skb->data);
 			_put_byte(&p, SEND_DATA_B3_REQ);
 			_put_slice(&p, skb->data, len);
 			_put_slice(&p, skb->data + len, dlen);
@@ -450,7 +450,7 @@
 			_put_byte(&p, SEND_MESSAGE);
 			_put_slice(&p, skb->data, len);
 		}
-		txlen = (__u8 *)p - (__u8 *)dma->sendbuf.dmabuf;
+		txlen = (u8 *)p - (u8 *)dma->sendbuf.dmabuf;
 #ifdef CONFIG_C4_DEBUG
 		printk(KERN_DEBUG "%s: tx put msg len=%d\n", card->name, txlen);
 #endif
@@ -496,7 +496,7 @@
 	_put_byte(&p, 0);
 	_put_byte(&p, 0);
 	_put_byte(&p, SEND_POLLACK);
-	skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+	skb_put(skb, (u8 *)p - (u8 *)skb->data);
 
 	skb_queue_tail(&card->dma->send_queue, skb);
 	c4_dispatch_tx(card);
@@ -511,9 +511,9 @@
 	avmctrl_info *cinfo;
 	struct sk_buff *skb;
 	void *p = dma->recvbuf.dmabuf;
-	__u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;
-	__u8 b1cmd =  _get_byte(&p);
-	__u32 cidx;
+	u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;
+	u8 b1cmd =  _get_byte(&p);
+	u32 cidx;
 
 
 #ifdef CONFIG_C4_DEBUG
@@ -674,7 +674,7 @@
 
 static void c4_handle_interrupt(avmcard *card)
 {
-	__u32 status = c4inmeml(card->mbase+DOORBELL);
+	u32 status = c4inmeml(card->mbase+DOORBELL);
 
 	if (status & DBELL_RESET_HOST) {
 		int i;
@@ -760,13 +760,13 @@
 	_put_word(&p, CAPI_MAXAPPL);
 	_put_word(&p, AVM_NCCI_PER_CHANNEL*30);
 	_put_word(&p, card->cardnr - 1);
-	skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+	skb_put(skb, (u8 *)p - (u8 *)skb->data);
 
 	skb_queue_tail(&card->dma->send_queue, skb);
 	c4_dispatch_tx(card);
 }
 
-static int queue_sendconfigword(avmcard *card, __u32 val)
+static int queue_sendconfigword(avmcard *card, u32 val)
 {
 	struct sk_buff *skb;
 	void *p;
@@ -782,7 +782,7 @@
 	_put_byte(&p, 0);
 	_put_byte(&p, SEND_CONFIG);
 	_put_word(&p, val);
-	skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+	skb_put(skb, (u8 *)p - (u8 *)skb->data);
 
 	skb_queue_tail(&card->dma->send_queue, skb);
 	c4_dispatch_tx(card);
@@ -808,7 +808,7 @@
 	_put_byte(&p, cval[1]);
 	_put_byte(&p, cval[2]);
 	_put_byte(&p, cval[3]);
-	skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+	skb_put(skb, (u8 *)p - (u8 *)skb->data);
 
 	skb_queue_tail(&card->dma->send_queue, skb);
 	c4_dispatch_tx(card);
@@ -817,7 +817,7 @@
 
 static int c4_send_config(avmcard *card, capiloaddatapart * config)
 {
-	__u8 val[4];
+	u8 val[4];
 	unsigned char *dp;
 	int left, retval;
 	
@@ -828,7 +828,7 @@
 
 	dp = config->data;
 	left = config->len;
-	while (left >= sizeof(__u32)) {
+	while (left >= sizeof(u32)) {
 	        if (config->user) {
 			retval = copy_from_user(val, dp, sizeof(val));
 			if (retval)
@@ -954,7 +954,7 @@
 
 
 void c4_register_appl(struct capi_ctr *ctrl,
-				__u16 appl,
+				u16 appl,
 				capi_register_params *rp)
 {
 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
@@ -985,7 +985,7 @@
 		_put_word(&p, nconn);
 		_put_word(&p, rp->datablkcnt);
 		_put_word(&p, rp->datablklen);
-		skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+		skb_put(skb, (u8 *)p - (u8 *)skb->data);
 
 		skb_queue_tail(&card->dma->send_queue, skb);
 		c4_dispatch_tx(card);
@@ -996,7 +996,7 @@
 
 /* ------------------------------------------------------------- */
 
-void c4_release_appl(struct capi_ctr *ctrl, __u16 appl)
+void c4_release_appl(struct capi_ctr *ctrl, u16 appl)
 {
 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
 	avmcard *card = cinfo->card;
@@ -1016,7 +1016,7 @@
 		_put_byte(&p, SEND_RELEASE);
 		_put_word(&p, appl);
 
-		skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+		skb_put(skb, (u8 *)p - (u8 *)skb->data);
 		skb_queue_tail(&card->dma->send_queue, skb);
 		c4_dispatch_tx(card);
 	}
@@ -1056,7 +1056,7 @@
 {
 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
 	avmcard *card = cinfo->card;
-	__u8 flag;
+	u8 flag;
 	int len = 0;
 	char *s;
 
@@ -1085,7 +1085,7 @@
 	   len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
 
 	if (card->cardtype != avm_m1) {
-        	flag = ((__u8 *)(ctrl->profile.manu))[3];
+        	flag = ((u8 *)(ctrl->profile.manu))[3];
         	if (flag)
 			len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n",
 			"protocol",
@@ -1099,7 +1099,7 @@
 			);
 	}
 	if (card->cardtype != avm_m1) {
-        	flag = ((__u8 *)(ctrl->profile.manu))[5];
+        	flag = ((u8 *)(ctrl->profile.manu))[5];
 		if (flag)
 			len += sprintf(page+len, "%-16s%s%s%s%s\n",
 			"linetype",
diff -Nru a/drivers/isdn/hardware/avm/t1isa.c b/drivers/isdn/hardware/avm/t1isa.c
--- a/drivers/isdn/hardware/avm/t1isa.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/isdn/hardware/avm/t1isa.c	Tue Apr 30 17:10:25 2002
@@ -484,14 +484,14 @@
 	avmcard *card = cinfo->card;
 	unsigned int port = card->port;
 	unsigned long flags;
-	__u16 len = CAPIMSG_LEN(skb->data);
-	__u8 cmd = CAPIMSG_COMMAND(skb->data);
-	__u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
+	u16 len = CAPIMSG_LEN(skb->data);
+	u8 cmd = CAPIMSG_COMMAND(skb->data);
+	u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
 
 	save_flags(flags);
 	cli();
 	if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
-		__u16 dlen = CAPIMSG_DATALEN(skb->data);
+		u16 dlen = CAPIMSG_DATALEN(skb->data);
 		b1_put_byte(port, SEND_DATA_B3_REQ);
 		t1_put_slice(port, skb->data, len);
 		t1_put_slice(port, skb->data + len, dlen);
diff -Nru a/drivers/md/lvm-snap.c b/drivers/md/lvm-snap.c
--- a/drivers/md/lvm-snap.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/md/lvm-snap.c	Tue Apr 30 17:10:25 2002
@@ -26,7 +26,7 @@
  *
  *    05/07/2000 - implemented persistent snapshot support
  *    23/11/2000 - used cpu_to_le64 rather than my own macro
- *    25/01/2001 - Put LockPage back in
+ *    25/01/2001 - Put SetPageLocked back in
  *    01/02/2001 - A dropped snapshot is now set as inactive
  *    12/03/2001 - lvm_pv_get_number changes:
  *                 o made it static
@@ -34,6 +34,7 @@
  *                 o pv number is returned in new uint * arg
  *                 o -1 returned on error
  *                 lvm_snapshot_fill_COW_table has a return value too.
+ *    25/02/2002 - s/LockPage/SetPageLocked/ - akpm@zip.com.au
  *
  */
 
@@ -451,7 +452,7 @@
 			goto out;
 
 		iobuf->maplist[i] = page;
-		LockPage(page);
+		SetPageLocked(page);
 		iobuf->nr_pages++;
 	}
 	iobuf->offset = 0;
diff -Nru a/drivers/md/md.c b/drivers/md/md.c
--- a/drivers/md/md.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/md/md.c	Tue Apr 30 17:10:25 2002
@@ -488,8 +488,8 @@
 			(filler_t *)mapping->a_ops->readpage, NULL);
 	if (IS_ERR(page))
 		goto out;
-	wait_on_page(page);
-	if (!Page_Uptodate(page))
+	wait_on_page_locked(page);
+	if (!PageUptodate(page))
 		goto fail;
 	if (PageError(page))
 		goto fail;
@@ -948,14 +948,14 @@
 						offs + MD_SB_BYTES);
 	if (error)
 		goto unlock;
-	UnlockPage(page);
-	wait_on_page(page);
+	unlock_page(page);
+	wait_on_page_locked(page);
 	page_cache_release(page);
 	fsync_bdev(bdev);
 skip:
 	return 0;
 unlock:
-	UnlockPage(page);
+	unlock_page(page);
 	page_cache_release(page);
 fail:
 	printk("md: write_disk_sb failed for device %s\n", partition_name(dev));
@@ -1521,6 +1521,7 @@
 	mdp_super_t *sb = mddev->sb;
 	struct list_head *tmp;
 	mdk_rdev_t *rdev;
+	unsigned long *ra_pages;
 
 	/*
 	 * Do device size calculation. Bail out if too small.
@@ -1577,7 +1578,10 @@
 	if (!md_size[mdidx(mddev)])
 		md_size[mdidx(mddev)] = sb->size * data_disks;
 
-	readahead = (blk_get_readahead(rdev->bdev) * 512) / PAGE_SIZE;
+	readahead = (VM_MAX_READAHEAD * 1024) / PAGE_SIZE;
+	ra_pages = blk_get_ra_pages(rdev->dev);
+	if (ra_pages)
+		readahead = (*ra_pages * PAGE_CACHE_SIZE) / PAGE_SIZE;
 	if (!sb->level || (sb->level == 4) || (sb->level == 5)) {
 		readahead = (mddev->sb->chunk_size>>PAGE_SHIFT) * 4 * data_disks;
 		if (readahead < data_disks * (MAX_SECTORS>>(PAGE_SHIFT-9))*2)
diff -Nru a/drivers/md/raid5.c b/drivers/md/raid5.c
--- a/drivers/md/raid5.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/md/raid5.c	Tue Apr 30 17:10:25 2002
@@ -166,7 +166,6 @@
 		if (!bh)
 			return 1;
 		memset(bh, 0, sizeof (struct buffer_head));
-		init_waitqueue_head(&bh->b_wait);
 		if ((page = alloc_page(priority)))
 			bh->b_data = page_address(page);
 		else {
@@ -211,7 +210,7 @@
 			       buffer_locked(sh->bh_cache[i]));
 			BUG();
 		}
-		clear_bit(BH_Uptodate, &sh->bh_cache[i]->b_state);
+		clear_buffer_uptodate(sh->bh_cache[i]);
 		raid5_build_block(sh, i);
 	}
 	insert_hash(conf, sh);
@@ -411,7 +410,7 @@
 			buffer = NULL;
 		spin_unlock_irqrestore(&conf->device_lock, flags);
 		if (sh->bh_page[i]==NULL)
-			set_bit(BH_Uptodate, &bh->b_state);
+			set_buffer_uptodate(bh);
 		if (buffer) {
 			if (buffer->b_page != bh->b_page)
 				memcpy(buffer->b_data, bh->b_data, bh->b_size);
@@ -419,16 +418,16 @@
 		}
 	} else {
 		md_error(conf->mddev, bh->b_bdev);
-		clear_bit(BH_Uptodate, &bh->b_state);
+		clear_buffer_uptodate(bh);
 	}
 	/* must restore b_page before unlocking buffer... */
 	if (sh->bh_page[i]) {
 		bh->b_page = sh->bh_page[i];
 		bh->b_data = page_address(bh->b_page);
 		sh->bh_page[i] = NULL;
-		clear_bit(BH_Uptodate, &bh->b_state);
+		clear_buffer_uptodate(bh);
 	}
-	clear_bit(BH_Lock, &bh->b_state);
+	clear_buffer_locked(bh);
 	set_bit(STRIPE_HANDLE, &sh->state);
 	release_stripe(sh);
 }
@@ -453,7 +452,7 @@
 	md_spin_lock_irqsave(&conf->device_lock, flags);
 	if (!uptodate)
 		md_error(conf->mddev, bh->b_bdev);
-	clear_bit(BH_Lock, &bh->b_state);
+	clear_buffer_locked(bh);
 	set_bit(STRIPE_HANDLE, &sh->state);
 	__release_stripe(conf, sh);
 	md_spin_unlock_irqrestore(&conf->device_lock, flags);
@@ -474,7 +473,6 @@
 
 	bh->b_state	= (1 << BH_Req) | (1 << BH_Mapped);
 	bh->b_size	= sh->size;
-	bh->b_list	= BUF_LOCKED;
 	return bh;
 }
 
@@ -683,7 +681,7 @@
 	}
 	if (count != 1)
 		xor_block(count, bh_ptr);
-	set_bit(BH_Uptodate, &sh->bh_cache[dd_idx]->b_state);
+	set_buffer_uptodate(sh->bh_cache[dd_idx]);
 }
 
 static void compute_parity(struct stripe_head *sh, int method)
@@ -742,8 +740,8 @@
 			memcpy(bh->b_data,
 			       bdata,sh->size);
 			bh_kunmap(chosen[i]);
-			set_bit(BH_Lock, &bh->b_state);
-			mark_buffer_uptodate(bh, 1);
+			set_buffer_locked(bh);
+			set_buffer_uptodate(bh);
 		}
 
 	switch(method) {
@@ -766,10 +764,10 @@
 		xor_block(count, bh_ptr);
 	
 	if (method != CHECK_PARITY) {
-		mark_buffer_uptodate(sh->bh_cache[pd_idx], 1);
-		set_bit(BH_Lock, &sh->bh_cache[pd_idx]->b_state);
+		set_buffer_uptodate(sh->bh_cache[pd_idx]);
+		set_buffer_locked(sh->bh_cache[pd_idx]);
 	} else
-		mark_buffer_uptodate(sh->bh_cache[pd_idx], 0);
+		clear_buffer_uptodate(sh->bh_cache[pd_idx]);
 }
 
 static void add_stripe_bh (struct stripe_head *sh, struct buffer_head *bh, int dd_idx, int rw)
@@ -956,7 +954,7 @@
 					compute_block(sh, i);
 					uptodate++;
 				} else if (conf->disks[i].operational) {
-					set_bit(BH_Lock, &bh->b_state);
+					set_buffer_locked(bh);
 					action[i] = READ+1;
 					/* if I am just reading this block and we don't have
 					   a failed drive, or any pending writes then sidestep the cache */
@@ -1012,7 +1010,7 @@
 					if (test_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
 					{
 						PRINTK("Read_old block %d for r-m-w\n", i);
-						set_bit(BH_Lock, &bh->b_state);
+						set_buffer_locked(bh);
 						action[i] = READ+1;
 						locked++;
 					} else {
@@ -1031,7 +1029,7 @@
 					if (test_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
 					{
 						PRINTK("Read_old block %d for Reconstruct\n", i);
-						set_bit(BH_Lock, &bh->b_state);
+						set_buffer_locked(bh);
 						action[i] = READ+1;
 						locked++;
 					} else {
@@ -1095,7 +1093,7 @@
 			if (uptodate != disks)
 				BUG();
 			bh = sh->bh_cache[failed_num];
-			set_bit(BH_Lock, &bh->b_state);
+			set_buffer_locked(bh);
 			action[failed_num] = WRITE+1;
 			locked++;
 			set_bit(STRIPE_INSYNC, &sh->state);
@@ -1147,7 +1145,7 @@
 				generic_make_request(action[i]-1, bh);
 			} else {
 				PRINTK("skip op %d on disc %d for sector %ld\n", action[i]-1, i, sh->sector);
-				clear_bit(BH_Lock, &bh->b_state);
+				clear_buffer_locked(bh);
 				set_bit(STRIPE_HANDLE, &sh->state);
 			}
 		}
@@ -1224,7 +1222,7 @@
 		handle_stripe(sh);
 		release_stripe(sh);
 	} else
-		bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state));
+		bh->b_end_io(bh, buffer_uptodate(bh));
 	return 0;
 }
 
diff -Nru a/drivers/mtd/devices/blkmtd.c b/drivers/mtd/devices/blkmtd.c
--- a/drivers/mtd/devices/blkmtd.c	Tue Apr 30 17:10:23 2002
+++ b/drivers/mtd/devices/blkmtd.c	Tue Apr 30 17:10:23 2002
@@ -175,9 +175,9 @@
   DEBUG(2, "blkmtd: readpage called, dev = `%s' page = %p index = %ld\n",
 	bdevname(rawdevice->binding), page, page->index);
 
-  if(Page_Uptodate(page)) {
+  if(PageUptodate(page)) {
     DEBUG(2, "blkmtd: readpage page %ld is already upto date\n", page->index);
-    UnlockPage(page);
+    unlock_page(page);
     return 0;
   }
 
@@ -203,7 +203,7 @@
 	}
 	SetPageUptodate(page);
 	flush_dcache_page(page);
-	UnlockPage(page);
+	unlock_page(page);
 	spin_unlock(&mbd_writeq_lock);
 	return 0;
       }
@@ -281,7 +281,7 @@
     err = 0;
   }
   flush_dcache_page(page);
-  UnlockPage(page);
+  unlock_page(page);
   DEBUG(2, "blkmtd: readpage: finished, err = %d\n", err);
   return 0;
 }
@@ -416,7 +416,7 @@
       write_queue_tail %= write_queue_sz;
       if(!item->iserase) {
 	for(i = 0 ; i < item->pagecnt; i++) {
-	  UnlockPage(item->pages[i]);
+	  unlock_page(item->pages[i]);
 	  __free_pages(item->pages[i], 0);
 	}
 	kfree(item->pages);
@@ -470,7 +470,7 @@
       outpage = alloc_pages(GFP_KERNEL, 0);
       if(!outpage) {
 	while(i--) {
-	  UnlockPage(new_pages[i]);
+	  unlock_page(new_pages[i]);
 	  __free_pages(new_pages[i], 0);
 	}
 	kfree(new_pages);
@@ -607,7 +607,7 @@
     if(!err) {
       while(pagecnt--) {
 	SetPageUptodate(pages[pagecnt]);
-	UnlockPage(pages[pagecnt]);
+	unlock_page(pages[pagecnt]);
 	page_cache_release(pages[pagecnt]);
 	flush_dcache_page(pages[pagecnt]);
       }
@@ -662,8 +662,8 @@
     if(IS_ERR(page)) {
       return PTR_ERR(page);
     }
-    wait_on_page(page);
-    if(!Page_Uptodate(page)) {
+    wait_on_page_locked(page);
+    if(!PageUptodate(page)) {
       /* error reading page */
       printk("blkmtd: read: page not uptodate\n");
       page_cache_release(page);
@@ -806,7 +806,7 @@
       }
       memcpy(page_address(page), buf, PAGE_SIZE);
       pages[pagecnt++] = page;
-      UnlockPage(page);
+      unlock_page(page);
       SetPageUptodate(page);
       pagenr++;
       pagesc--;
@@ -962,7 +962,7 @@
     kfree(write_queue);
 
   if(erase_page) {
-    UnlockPage(erase_page);
+    unlock_page(erase_page);
     __free_pages(erase_page, 0);
   }
   printk("blkmtd: unloaded for %s\n", device);
diff -Nru a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
--- a/drivers/net/ppp_generic.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/net/ppp_generic.c	Tue Apr 30 17:10:25 2002
@@ -381,6 +381,8 @@
 	ssize_t ret;
 	struct sk_buff *skb = 0;
 
+	ret = count;
+
 	if (pf == 0)
 		return -ENXIO;
 	add_wait_queue(&pf->rwait, &wait);
diff -Nru a/drivers/net/tun.c b/drivers/net/tun.c
--- a/drivers/net/tun.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/net/tun.c	Tue Apr 30 17:10:25 2002
@@ -1,6 +1,6 @@
 /*
  *  TUN - Universal TUN/TAP device driver.
- *  Copyright (C) 1999-2000 Maxim Krasnyansky <max_mk@yahoo.com>
+ *  Copyright (C) 1999-2002 Maxim Krasnyansky <maxk@qualcomm.com>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -12,7 +12,7 @@
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  *  GNU General Public License for more details.
  *
- *  $Id: tun.c,v 1.12 2001/03/08 03:29:27 maxk Exp $
+ *  $Id: tun.c,v 1.15 2002/03/01 02:44:24 maxk Exp $
  */
 
 /*
@@ -20,7 +20,7 @@
  *    Modifications for 2.3.99-pre5 kernel.
  */
 
-#define TUN_VER "1.4"
+#define TUN_VER "1.5"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -181,50 +181,26 @@
 }
 
 /* Get packet from user space buffer(already verified) */
-static __inline__ ssize_t
-tun_get_user(struct tun_struct *tun, const struct iovec *iov,
-	     unsigned long count, size_t total)
+static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv, size_t count)
 {
 	struct tun_pi pi = { 0, __constant_htons(ETH_P_IP) };
-	const struct iovec *vector = &iov[0];
-	register const char *ptr = vector->iov_base;
-	register int len = vector->iov_len;
 	struct sk_buff *skb;
-	ssize_t sent = 0;
+	size_t len = count;
 
 	if (!(tun->flags & TUN_NO_PI)) {
 		if ((len -= sizeof(pi)) < 0)
 			return -EINVAL;
 
-		copy_from_user(&pi, ptr, sizeof(pi));
-		ptr += sizeof(pi);
-
-		if (len == 0) {
-			vector++;
-			count--;
-
-			ptr = vector->iov_base;
-			len = vector->iov_len;
-		}
+		memcpy_fromiovec((void *)&pi, iv, sizeof(pi));
 	}
  
-	if (!(skb = alloc_skb(total + 2, GFP_KERNEL))) {
+	if (!(skb = alloc_skb(len + 2, GFP_KERNEL))) {
 		tun->stats.rx_dropped++;
 		return -ENOMEM;
 	}
 
 	skb_reserve(skb, 2);
-
-	while (count > 0) {
-		copy_from_user(skb_put(skb, len), ptr, len); 
-		sent += len;
-
-		vector++;
-		count--;
-
-		ptr = vector->iov_base;
-		len = vector->iov_len;
-	}
+	memcpy_fromiovec(skb_put(skb, len), iv, len);
 
 	skb->dev = &tun->dev;
 	switch (tun->flags & TUN_TYPE_MASK) {
@@ -243,60 +219,48 @@
 	netif_rx_ni(skb);
    
 	tun->stats.rx_packets++;
-	tun->stats.rx_bytes += sent;
+	tun->stats.rx_bytes += len;
 
-	return total;
+	return count;
 } 
 
-/* Write */
-static ssize_t tun_chr_write(struct file * file, const char * buf, 
-			     size_t count, loff_t *pos)
-{
-	struct tun_struct *tun = (struct tun_struct *)file->private_data;
-	struct iovec iov;
-
-	if (!tun)
-		return -EBADFD;
-
-	DBG(KERN_INFO "%s: tun_chr_write %d\n", tun->name, count);
-
-	if (verify_area(VERIFY_READ, buf, count))
-		return -EFAULT;
-
-	iov.iov_base = (char *) buf;
-	iov.iov_len = count;
-
-	return tun_get_user(tun, &iov, 1, count);
-}
-
 /* Writev */
-static ssize_t tun_chr_writev(struct file * file, const struct iovec *iov,
+static ssize_t tun_chr_writev(struct file * file, const struct iovec *iv, 
 			      unsigned long count, loff_t *pos)
 {
 	struct tun_struct *tun = (struct tun_struct *)file->private_data;
-	size_t total = 0;
 	unsigned long i;
+	size_t len;
 
 	if (!tun)
 		return -EBADFD;
 
-	for (i = 0; i < count; i++) {
-		if (verify_area(VERIFY_READ, iov[i].iov_base, iov[i].iov_len))
+	DBG(KERN_INFO "%s: tun_chr_write %d\n", tun->name, count);
+
+	for (i = 0, len = 0; i < count; i++) {
+		if (verify_area(VERIFY_READ, iv[i].iov_base, iv[i].iov_len))
 			return -EFAULT;
-		total += iov[i].iov_len;
+		len += iv[i].iov_len;
 	}
 
-	return tun_get_user(tun, iov, count, total);
+	return tun_get_user(tun, (struct iovec *) iv, len);
+}
+
+/* Write */
+static ssize_t tun_chr_write(struct file * file, const char * buf, 
+			     size_t count, loff_t *pos)
+{
+	struct iovec iv = { (void *) buf, count };
+	return tun_chr_writev(file, &iv, 1, pos);
 }
 
-/* Put packet to user space buffer(already verified) */
+/* Put packet to the user space buffer (already verified) */
 static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
 				       struct sk_buff *skb,
-				       char *buf, int count)
+				       struct iovec *iv, int len)
 {
 	struct tun_pi pi = { 0, skb->protocol };
-	int len = count, total = 0;
-	char *ptr = buf;
+	ssize_t total = 0;
 
 	if (!(tun->flags & TUN_NO_PI)) {
 		if ((len -= sizeof(pi)) < 0)
@@ -307,14 +271,13 @@
 			pi.flags |= TUN_PKT_STRIP;
 		}
  
-		copy_to_user(ptr, &pi, sizeof(pi));
-
+		memcpy_toiovec(iv, (void *) &pi, sizeof(pi));
 		total += sizeof(pi);
-		ptr += sizeof(pi);
 	}       
 
-	len = MIN(skb->len, len); 
-	copy_to_user(ptr, skb->data, len); 
+	len = MIN(skb->len, len);
+
+	skb_copy_datagram_iovec(skb, 0, iv, len);
 	total += len;
 
 	tun->stats.tx_packets++;
@@ -323,22 +286,29 @@
 	return total;
 }
 
-/* Read */
-static ssize_t tun_chr_read(struct file * file, char * buf, 
-			    size_t count, loff_t *pos)
+/* Readv */
+static ssize_t tun_chr_readv(struct file *file, const struct iovec *iv,
+			    unsigned long count, loff_t *pos)
 {
 	struct tun_struct *tun = (struct tun_struct *)file->private_data;
 	DECLARE_WAITQUEUE(wait, current);
 	struct sk_buff *skb;
-	ssize_t ret = 0;
+	ssize_t len, ret = 0;
+	unsigned long i;
 
 	if (!tun)
 		return -EBADFD;
 
 	DBG(KERN_INFO "%s: tun_chr_read\n", tun->name);
 
+	for (i = 0, len = 0; i < count; i++) {
+		if (verify_area(VERIFY_WRITE, iv[i].iov_base, iv[i].iov_len))
+			return -EFAULT;
+		len += iv[i].iov_len;
+	}
+
 	add_wait_queue(&tun->read_wait, &wait);
-	while (count) {
+	while (len) {
 		current->state = TASK_INTERRUPTIBLE;
 
 		/* Read frames from the queue */
@@ -358,10 +328,7 @@
 		}
 		netif_start_queue(&tun->dev);
 
-		if (!verify_area(VERIFY_WRITE, buf, count))
-			ret = tun_put_user(tun, skb, buf, count);
-		else
-			ret = -EFAULT;
+		ret = tun_put_user(tun, skb, (struct iovec *) iv, len);
 
 		kfree_skb(skb);
 		break;
@@ -373,6 +340,14 @@
 	return ret;
 }
 
+/* Read */
+static ssize_t tun_chr_read(struct file * file, char * buf, 
+			    size_t count, loff_t *pos)
+{
+	struct iovec iv = { buf, count };
+	return tun_chr_readv(file, &iv, 1, pos);
+}
+
 static int tun_set_iff(struct file *file, struct ifreq *ifr)
 {
 	struct tun_struct *tun;
@@ -592,6 +567,7 @@
 	owner:	THIS_MODULE,	
 	llseek:	no_llseek,
 	read:	tun_chr_read,
+	readv:	tun_chr_readv,
 	write:	tun_chr_write,
 	writev:	tun_chr_writev,
 	poll:	tun_chr_poll,
@@ -611,7 +587,7 @@
 int __init tun_init(void)
 {
 	printk(KERN_INFO "Universal TUN/TAP device driver %s " 
-	       "(C)1999-2001 Maxim Krasnyansky\n", TUN_VER);
+	       "(C)1999-2002 Maxim Krasnyansky\n", TUN_VER);
 
 	if (misc_register(&tun_miscdev)) {
 		printk(KERN_ERR "tun: Can't register misc device %d\n", TUN_MINOR);
diff -Nru a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile
--- a/drivers/net/wan/Makefile	Tue Apr 30 17:10:23 2002
+++ b/drivers/net/wan/Makefile	Tue Apr 30 17:10:23 2002
@@ -7,7 +7,8 @@
 
 O_TARGET := wan.o
 
-export-objs :=	z85230.o syncppp.o comx.o sdladrv.o cycx_drv.o hdlc_generic.o
+export-objs :=	z85230.o syncppp.o comx.o sdladrv.o cycx_drv.o hdlc_generic.o \
+		dlci.o
 
 wanpipe-y			:= sdlamain.o sdla_ft1.o
 wanpipe-$(CONFIG_WANPIPE_X25)	+= sdla_x25.o
diff -Nru a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c
--- a/drivers/net/wan/dlci.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/net/wan/dlci.c	Tue Apr 30 17:10:25 2002
@@ -96,6 +96,8 @@
 	return(0);
 }
 
+EXPORT_SYMBOL(register_frad);
+
 int unregister_frad(const char *name)
 {
 	int i;
diff -Nru a/drivers/net/wireless/Config.help b/drivers/net/wireless/Config.help
--- a/drivers/net/wireless/Config.help	Tue Apr 30 17:10:23 2002
+++ b/drivers/net/wireless/Config.help	Tue Apr 30 17:10:23 2002
@@ -55,6 +55,14 @@
   Support for these adaptors is so far still incomplete and buggy.
   You have been warned.
 
+Prism 2.5 PCI 802.11b adaptor support
+CONFIG_PCI_HERMES
+  Enable support for PCI and mini-PCI 802.11b wireless NICs based on
+  the Prism 2.5 chipset.  These are true PCI cards, not the 802.11b
+  PCMCIA cards bundled with PCI<->PCMCIA adaptors which are also
+  common.  Some of the built-in wireless adaptors in laptops are of
+  this variety.
+
 CONFIG_PCMCIA_HERMES
   A driver for "Hermes" chipset based PCMCIA wireless adaptors, such
   as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/
diff -Nru a/drivers/net/wireless/Config.in b/drivers/net/wireless/Config.in
--- a/drivers/net/wireless/Config.in	Tue Apr 30 17:10:25 2002
+++ b/drivers/net/wireless/Config.in	Tue Apr 30 17:10:25 2002
@@ -20,6 +20,7 @@
 
 if [ "$CONFIG_PCI" = "y" ]; then
    dep_tristate '    Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.)' CONFIG_PLX_HERMES $CONFIG_HERMES $CONFIG_EXPERIMENTAL
+   dep_tristate '    Prism 2.5 PCI 802.11b adaptor support' CONFIG_PCI_HERMES $CONFIG_HERMES $CONFIG_EXPERIMENTAL
 fi
 
 # If Pcmcia is compiled in, offer Pcmcia cards...
diff -Nru a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
--- a/drivers/net/wireless/Makefile	Tue Apr 30 17:10:25 2002
+++ b/drivers/net/wireless/Makefile	Tue Apr 30 17:10:25 2002
@@ -23,6 +23,7 @@
 obj-$(CONFIG_PCMCIA_HERMES)	+= orinoco_cs.o
 obj-$(CONFIG_APPLE_AIRPORT)	+= airport.o
 obj-$(CONFIG_PLX_HERMES)	+= orinoco_plx.o
+obj-$(CONFIG_PCI_HERMES)	+= orinoco_pci.o
 
 obj-$(CONFIG_AIRO)		+= airo.o
 obj-$(CONFIG_AIRO_CS)		+= airo_cs.o airo.o
diff -Nru a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c
--- a/drivers/net/wireless/airport.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/net/wireless/airport.c	Tue Apr 30 17:10:25 2002
@@ -1,4 +1,4 @@
-/* airport.c 0.06f
+/* airport.c 0.11a
  *
  * A driver for "Hermes" chipset based Apple Airport wireless
  * card.
@@ -11,6 +11,8 @@
  *  0.06 : fix possible hang on powerup, add sleep support
  */
 
+#include <linux/config.h>
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -33,26 +35,28 @@
 #include <linux/pmu.h>
 
 #include <asm/prom.h>
-#include <asm/feature.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
 #include <asm/irq.h>
 
 #include "hermes.h"
 #include "orinoco.h"
 
-static char version[] __initdata = "airport.c 0.06f (Benjamin Herrenschmidt <benh@kernel.crashing.org>)";
+static char version[] __initdata = "airport.c 0.11a (Benjamin Herrenschmidt <benh@kernel.crashing.org>)";
 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
 MODULE_DESCRIPTION("Driver for the Apple Airport wireless card.");
 MODULE_LICENSE("Dual MPL/GPL");
 EXPORT_NO_SYMBOLS;
 
-typedef struct dldwd_card {
+#define AIRPORT_IO_LEN	(0x1000)	/* one page */
+
+struct airport {
 	struct device_node* node;
+	void *vaddr;
 	int irq_requested;
 	int ndev_registered;
 	int open;
-	/* Common structure (fully included), see orinoco.h */
-	struct dldwd_priv priv;
-} dldwd_card_t;
+};
 
 #ifdef CONFIG_PMAC_PBOOK
 static int airport_sleep_notify(struct pmu_sleep_notifier *self, int when);
@@ -65,9 +69,8 @@
  * Function prototypes
  */
 
-static dldwd_priv_t* airport_attach(struct device_node *of_node);
-static void airport_detach(dldwd_priv_t* priv);
-static int airport_init(struct net_device *dev);
+static struct net_device *airport_attach(struct device_node *of_node);
+static void airport_detach(struct net_device *dev);
 static int airport_open(struct net_device *dev);
 static int airport_stop(struct net_device *dev);
 
@@ -81,44 +84,28 @@
    device numbers are used to derive the corresponding array index.
 */
 
-static dldwd_priv_t *airport_dev;
-
-static int airport_init(struct net_device *dev)
-{
-	dldwd_priv_t *priv = dev->priv;
-	int rc;
-	
-	TRACE_ENTER(priv->ndev.name);
-
-	MOD_INC_USE_COUNT;
-
-	rc = dldwd_init(dev);
-	if (!rc)
-		priv->hw_ready = 1;
-
-	MOD_DEC_USE_COUNT;
-
-	return rc;
-}
+static struct net_device *airport_dev;
 
 static int
 airport_open(struct net_device *dev)
 {
-	dldwd_priv_t *priv = dev->priv;
-	dldwd_card_t* card = (dldwd_card_t *)priv->card;
+	struct orinoco_private *priv = dev->priv;
+	struct airport* card = (struct airport *)priv->card;
 	int rc;
 
-	TRACE_ENTER(priv->ndev.name);
+	TRACE_ENTER(dev->name);
+
+	netif_device_attach(dev);
 
-	rc = dldwd_reset(priv);
+	rc = orinoco_reset(priv);
 	if (rc)
 		airport_stop(dev);
 	else {
 		card->open = 1;
-		netif_device_attach(dev);
+		netif_start_queue(dev);
 	}
 
-//	TRACE_EXIT(priv->ndev.name);
+	TRACE_EXIT(dev->name);
 
 	return rc;
 }
@@ -126,16 +113,16 @@
 static int
 airport_stop(struct net_device *dev)
 {
-	dldwd_priv_t *priv = dev->priv;
-	dldwd_card_t* card = (dldwd_card_t *)priv->card;
+	struct orinoco_private *priv = dev->priv;
+	struct airport* card = (struct airport *)priv->card;
 
-	TRACE_ENTER(priv->ndev.name);
+	TRACE_ENTER(dev->name);
 
 	netif_stop_queue(dev);
-	dldwd_shutdown(priv);
+	orinoco_shutdown(priv);
 	card->open = 0;
 
-	TRACE_EXIT(priv->ndev.name);
+	TRACE_EXIT(dev->name);
 
 	return 0;
 }
@@ -144,16 +131,14 @@
 static int
 airport_sleep_notify(struct pmu_sleep_notifier *self, int when)
 {
-	dldwd_priv_t *priv;
-	struct net_device *ndev;
-	dldwd_card_t* card;
+	struct net_device *dev = airport_dev;
+	struct orinoco_private *priv = (struct orinoco_private *)dev->priv;
+	struct hermes *hw = &priv->hw;
+	struct airport* card = (struct airport *)priv->card;
 	int rc;
 	
-	if (!airport_dev)
+	if (! airport_dev)
 		return PBOOK_SLEEP_OK;
-	priv = airport_dev;
-	ndev = &priv->ndev;
-	card = (dldwd_card_t *)priv->card;
 
 	switch (when) {
 	case PBOOK_SLEEP_REQUEST:
@@ -161,41 +146,42 @@
 	case PBOOK_SLEEP_REJECT:
 		break;
 	case PBOOK_SLEEP_NOW:
-		printk(KERN_INFO "%s: Airport entering sleep mode\n", ndev->name);
-		netif_device_detach(ndev);
-		if (card->open)
-			dldwd_shutdown(priv);
-		disable_irq(ndev->irq);
-		feature_set_airport_power(card->node, 0);
-		priv->hw_ready = 0;
+		printk(KERN_INFO "%s: Airport entering sleep mode\n", dev->name);
+		if (card->open) {
+			netif_stop_queue(dev);
+			orinoco_shutdown(priv);
+			netif_device_detach(dev);
+		}
+		disable_irq(dev->irq);
+		pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0);
 		break;
 	case PBOOK_WAKE:
-		printk(KERN_INFO "%s: Airport waking up\n", ndev->name);
-		feature_set_airport_power(card->node, 1);
+		printk(KERN_INFO "%s: Airport waking up\n", dev->name);
+		pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 1);
 		mdelay(200);
-		hermes_reset(&priv->hw);
-		priv->hw_ready = 1;		
-		rc = dldwd_reset(priv);
+		hermes_reset(hw);
+		rc = orinoco_reset(priv);
 		if (rc)
 			printk(KERN_ERR "airport: Error %d re-initing card !\n", rc);
 		else if (card->open)
-			netif_device_attach(ndev);
-		enable_irq(ndev->irq);
+			netif_device_attach(dev);
+		enable_irq(dev->irq);
 		break;
 	}
 	return PBOOK_SLEEP_OK;
 }
 #endif /* CONFIG_PMAC_PBOOK */
 
-static dldwd_priv_t*
+static struct net_device *
 airport_attach(struct device_node* of_node)
 {
-	dldwd_priv_t *priv;
-	struct net_device *ndev;
-	dldwd_card_t* card;
+	struct orinoco_private *priv;
+	struct net_device *dev;
+	struct airport *card;
+	unsigned long phys_addr;
 	hermes_t *hw;
 
-	TRACE_ENTER("dldwd");
+	TRACE_ENTER("orinoco");
 
 	if (of_node->n_addrs < 1 || of_node->n_intrs < 1) {
 		printk(KERN_ERR "airport: wrong interrupt/addresses in OF tree\n");
@@ -203,74 +189,77 @@
 	}
 
 	/* Allocate space for private device-specific data */
-	card = kmalloc(sizeof(*card), GFP_KERNEL);
-	if (!card) {
+	dev = alloc_orinocodev(sizeof(*card));
+	if (! dev) {
 		printk(KERN_ERR "airport: can't allocate device datas\n");
 		return NULL;
 	}
-	memset(card, 0, sizeof(*card));
+	priv = dev->priv;
+	card = priv->card;
 
-	priv = &(card->priv);
-	priv->card = card;
-	ndev = &priv->ndev;
 	hw = &priv->hw;
 	card->node = of_node;
 
-	/* Setup the common part */
-	if (dldwd_setup(priv) < 0) {
-		kfree(card);
+	if (! request_OF_resource(of_node, 0, " (airport)")) {
+		printk(KERN_ERR "airport: can't request IO resource !\n");
+		kfree(dev);
 		return NULL;
 	}
+	
+	dev->name[0] = '\0';	/* register_netdev will give us an ethX name */
+	SET_MODULE_OWNER(dev);
 
 	/* Overrides */
-	ndev->init = airport_init;
-	ndev->open = airport_open;
-	ndev->stop = airport_stop;
+	dev->open = airport_open;
+	dev->stop = airport_stop;
 
 	/* Setup interrupts & base address */
-	ndev->irq = of_node->intrs[0].line;
-	ndev->base_addr = (unsigned long)ioremap(of_node->addrs[0].address, 0x1000) - _IO_BASE;
+	dev->irq = of_node->intrs[0].line;
+	phys_addr = of_node->addrs[0].address; /* Physical address */
+	dev->base_addr = phys_addr;
+	card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN);
+	if (! card->vaddr) {
+		printk("airport: ioremap() failed\n");
+		goto failed;
+	}
 
-	hermes_struct_init(hw, ndev->base_addr);
+	hermes_struct_init(hw, (ulong)card->vaddr,
+			HERMES_MEM, HERMES_16BIT_REGSPACING);
 		
 	/* Power up card */
-	feature_set_airport_power(card->node, 1);
+	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 1);
 	current->state = TASK_UNINTERRUPTIBLE;
 	schedule_timeout(HZ);
 
 	/* Reset it before we get the interrupt */
 	hermes_reset(hw);
 
-	if (request_irq(ndev->irq, dldwd_interrupt, 0, "Airport", (void *)priv)) {
-		printk(KERN_ERR "airport: Couldn't get IRQ %d\n", ndev->irq);
+	if (request_irq(dev->irq, orinoco_interrupt, 0, "Airport", (void *)priv)) {
+		printk(KERN_ERR "airport: Couldn't get IRQ %d\n", dev->irq);
 		goto failed;
 	}
 	card->irq_requested = 1;
 	
-	/* register_netdev will give us an ethX name */
-	ndev->name[0] = '\0';
 	/* Tell the stack we exist */
-	if (register_netdev(ndev) != 0) {
+	if (register_netdev(dev) != 0) {
 		printk(KERN_ERR "airport: register_netdev() failed\n");
 		goto failed;
 	}
-	printk(KERN_DEBUG "airport: card registered for interface %s\n", ndev->name);
+	printk(KERN_DEBUG "airport: card registered for interface %s\n", dev->name);
 	card->ndev_registered = 1;
 
-	SET_MODULE_OWNER(ndev);
-
 	/* And give us the proc nodes for debugging */
-	if (dldwd_proc_dev_init(priv) != 0)
+	if (orinoco_proc_dev_init(priv) != 0)
 		printk(KERN_ERR "airport: Failed to create /proc node for %s\n",
-		       ndev->name);
+		       dev->name);
 
 #ifdef CONFIG_PMAC_PBOOK
 	pmu_register_sleep_notifier(&airport_sleep_notifier);
 #endif
-	return priv;
+	return dev;
 	
 failed:
-	airport_detach(priv);
+	airport_detach(dev);
 	return NULL;
 }				/* airport_attach */
 
@@ -279,32 +268,34 @@
   ======================================================================*/
 
 static void
-airport_detach(dldwd_priv_t *priv)
+airport_detach(struct net_device *dev)
 {
-	dldwd_card_t* card = (dldwd_card_t *)priv->card;
+	struct orinoco_private *priv = (struct orinoco_private *)dev->priv;
+	struct airport *card = (struct airport *)priv->card;
 
-	priv->hw_ready = 0;
-	
 	/* Unregister proc entry */
-	dldwd_proc_dev_cleanup(priv);
+	orinoco_proc_dev_cleanup(priv);
 
 #ifdef CONFIG_PMAC_PBOOK
 	pmu_unregister_sleep_notifier(&airport_sleep_notifier);
 #endif
 	if (card->ndev_registered)
-		unregister_netdev(&priv->ndev);
+		unregister_netdev(dev);
 	card->ndev_registered = 0;
 	
 	if (card->irq_requested)
-		free_irq(priv->ndev.irq, priv);
+		free_irq(dev->irq, priv);
 	card->irq_requested = 0;
 
-// FIXME
-//	if (ndev->base_addr)
-//		iounmap(ndev->base_addr + _IO_BASE);
-//	ndev->base_addr = 0;
+	if (card->vaddr)
+		iounmap(card->vaddr);
+	card->vaddr = 0;
+	
+	dev->base_addr = 0;
+
+	release_OF_resource(card->node, 0);
 	
-	feature_set_airport_power(card->node, 0);
+	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0);
 	current->state = TASK_UNINTERRUPTIBLE;
 	schedule_timeout(HZ);
 	
diff -Nru a/drivers/net/wireless/hermes.c b/drivers/net/wireless/hermes.c
--- a/drivers/net/wireless/hermes.c	Tue Apr 30 17:10:24 2002
+++ b/drivers/net/wireless/hermes.c	Tue Apr 30 17:10:24 2002
@@ -53,17 +53,18 @@
 
 #include "hermes.h"
 
-static char version[] __initdata = "hermes.c: 3 Oct 2001 David Gibson <hermes@gibson.dropbear.id.au>";
+static char version[] __initdata = "hermes.c: 5 Apr 2002 David Gibson <hermes@gibson.dropbear.id.au>";
 MODULE_DESCRIPTION("Low-level driver helper for Lucent Hermes chipset and Prism II HFA384x wireless MAC controller");
 MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>");
+#ifdef MODULE_LICENSE
 MODULE_LICENSE("Dual MPL/GPL");
+#endif
 
 /* These are maximum timeouts. Most often, card wil react much faster */
 #define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */
 #define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */
 #define CMD_COMPL_TIMEOUT (20000) /* in iterations of ~10us */
 #define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */
-#define BAP_BUSY_TIMEOUT (500) /* In iterations of ~1us */
 
 /*
  * Debugging helpers
@@ -75,9 +76,9 @@
 #include <stdarg.h>
 
 #define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ 0x%x: " , hw->iobase); \
-			printk(#stuff);} while (0)
+			printk(stuff);} while (0)
 
-#define DEBUG(lvl, stuff...) if ( (lvl) <= HERMES_DEBUG) DMSG(#stuff)
+#define DEBUG(lvl, stuff...) if ( (lvl) <= HERMES_DEBUG) DMSG(stuff)
 
 #else /* ! HERMES_DEBUG */
 
@@ -85,6 +86,8 @@
 
 #endif /* ! HERMES_DEBUG */
 
+#define IO_TYPE(hw)	((hw)->io_space ? "IO " : "MEM ")
+
 /*
  * Internal functions
  */
@@ -98,10 +101,17 @@
 */
 static int hermes_issue_cmd(hermes_t *hw, u16 cmd, u16 param0)
 {
+	int k = CMD_BUSY_TIMEOUT;
 	u16 reg;
 
-	/* First check that the command register is not busy */
+	/* First wait for the command register to unbusy */
 	reg = hermes_read_regn(hw, CMD);
+	while ( (reg & HERMES_CMD_BUSY) && k ) {
+		k--;
+		udelay(1);
+		reg = hermes_read_regn(hw, CMD);
+	}
+	DEBUG(3, "hermes_issue_cmd: did %d retries.\n", CMD_BUSY_TIMEOUT-k);
 	if (reg & HERMES_CMD_BUSY) {
 		return -EBUSY;
 	}
@@ -118,10 +128,19 @@
  * Function definitions
  */
 
-void hermes_struct_init(hermes_t *hw, uint io)
+void hermes_struct_init(hermes_t *hw, ulong address,
+			int io_space, int reg_spacing)
 {
-	hw->iobase = io;
+	hw->iobase = address;
+	hw->io_space = io_space;
+	hw->reg_spacing = reg_spacing;
 	hw->inten = 0x0;
+
+#ifdef HERMES_DEBUG_BUFFER
+	hw->dbufp = 0;
+	memset(&hw->dbuf, 0xff, sizeof(hw->dbuf));
+	memset(&hw->profile, 0, sizeof(hw->profile));
+#endif
 }
 
 int hermes_reset(hermes_t *hw)
@@ -188,8 +207,9 @@
 	}
 		
 	if (! (reg & HERMES_EV_CMD)) {
-		printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for card to reset (reg=0x%04x)!\n",
-		       hw->iobase, reg);
+		printk(KERN_ERR "hermes @ %s0x%lx: " 
+		       "Timeout waiting for card to reset (reg=0x%04x)!\n",
+		       IO_TYPE(hw), hw->iobase, reg);
 		err = -ETIMEDOUT;
 		goto out;
 	}
@@ -198,7 +218,8 @@
 
 	hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
 
-	err = status & HERMES_STATUS_RESULT;
+	if (status & HERMES_STATUS_RESULT)
+		err = -EIO;
 
  out:
 	return err;
@@ -215,16 +236,18 @@
 	int err;
 	int k;
 	u16 reg;
+	u16 status;
 
 	err = hermes_issue_cmd(hw, cmd, parm0);
 	if (err) {
 		if (! hermes_present(hw)) {
-			printk(KERN_WARNING "hermes @ 0x%x: Card removed while issuing command.\n",
-			       hw->iobase);
+			printk(KERN_WARNING "hermes @ %s0x%lx: "
+			       "Card removed while issuing command.\n",
+			       IO_TYPE(hw), hw->iobase);
 			err = -ENODEV;
 		} else 
-			printk(KERN_ERR "hermes @ 0x%x: CMD register busy in hermes_issue_command().\n",
-			       hw->iobase);
+			printk(KERN_ERR "hermes @ %s0x%lx: Error %d issuing command.\n",
+			       IO_TYPE(hw), hw->iobase, err);
 		goto out;
 	}
 
@@ -237,27 +260,33 @@
 	}
 
 	if (! hermes_present(hw)) {
-		printk(KERN_WARNING "hermes @ 0x%x: Card removed while waiting for command completion.\n",
-		       hw->iobase);
+		printk(KERN_WARNING "hermes @ %s0x%lx: "
+		       "Card removed while waiting for command completion.\n",
+		       IO_TYPE(hw), hw->iobase);
 		err = -ENODEV;
 		goto out;
 	}
 		
 	if (! (reg & HERMES_EV_CMD)) {
-		printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for command completion.\n",
-		       hw->iobase);
+		printk(KERN_ERR "hermes @ %s0x%lx: "
+		       "Timeout waiting for command completion.\n",
+		       IO_TYPE(hw), hw->iobase);
 		err = -ETIMEDOUT;
 		goto out;
 	}
 
-	resp->status = hermes_read_regn(hw, STATUS);
-	resp->resp0 = hermes_read_regn(hw, RESP0);
-	resp->resp1 = hermes_read_regn(hw, RESP1);
-	resp->resp2 = hermes_read_regn(hw, RESP2);
+	status = hermes_read_regn(hw, STATUS);
+	if (resp) {
+		resp->status = status;
+		resp->resp0 = hermes_read_regn(hw, RESP0);
+		resp->resp1 = hermes_read_regn(hw, RESP1);
+		resp->resp2 = hermes_read_regn(hw, RESP2);
+	}
 
 	hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
 
-	err = resp->status & HERMES_STATUS_RESULT;
+	if (status & HERMES_STATUS_RESULT)
+		err = -EIO;
 
  out:
 	return err;
@@ -266,17 +295,17 @@
 int hermes_allocate(hermes_t *hw, u16 size, u16 *fid)
 {
 	int err = 0;
-	hermes_response_t resp;
 	int k;
 	u16 reg;
 	
 	if ( (size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX) )
 		return -EINVAL;
 
-	err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, &resp);
+	err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, NULL);
 	if (err) {
-		printk(KERN_WARNING "hermes @ 0x%x: Frame allocation command failed (0x%X).\n",
-		       hw->iobase, err);
+		printk(KERN_WARNING "hermes @ %s0x%lx: "
+		       "Frame allocation command failed (0x%X).\n",
+		       IO_TYPE(hw), hw->iobase, err);
 		return err;
 	}
 
@@ -289,14 +318,16 @@
 	}
 	
 	if (! hermes_present(hw)) {
-		printk(KERN_WARNING "hermes @ 0x%x: Card removed waiting for frame allocation.\n",
-		       hw->iobase);
+		printk(KERN_WARNING "hermes @ %s0x%lx: "
+		       "Card removed waiting for frame allocation.\n",
+		       IO_TYPE(hw), hw->iobase);
 		return -ENODEV;
 	}
 		
 	if (! (reg & HERMES_EV_ALLOC)) {
-		printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for frame allocation\n",
-		       hw->iobase);
+		printk(KERN_ERR "hermes @ %s0x%lx: "
+		       "Timeout waiting for frame allocation\n",
+		       IO_TYPE(hw), hw->iobase);
 		return -ETIMEDOUT;
 	}
 
@@ -306,13 +337,14 @@
 	return 0;
 }
 
+
 /* Set up a BAP to read a particular chunk of data from card's internal buffer.
  *
  * Returns: < 0 on internal failure (errno), 0 on success, >0 on error
  * from firmware
  *
  * Callable from any context */
-int hermes_bap_seek(hermes_t *hw, int bap, u16 id, u16 offset)
+static int hermes_bap_seek(hermes_t *hw, int bap, u16 id, u16 offset)
 {
 	int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0;
 	int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0;
@@ -323,14 +355,27 @@
 	if ( (offset > HERMES_BAP_OFFSET_MAX) || (offset % 2) )
 		return -EINVAL;
 
-	k = BAP_BUSY_TIMEOUT;
+	k = HERMES_BAP_BUSY_TIMEOUT;
 	reg = hermes_read_reg(hw, oreg);
-	while ((reg & HERMES_OFFSET_BUSY) & k) {
+	while ((reg & HERMES_OFFSET_BUSY) && k) {
 		k--;
 		udelay(1);
 		reg = hermes_read_reg(hw, oreg);
 	}
 
+#ifdef HERMES_DEBUG_BUFFER
+	hw->profile[HERMES_BAP_BUSY_TIMEOUT - k]++;
+
+	if (k < HERMES_BAP_BUSY_TIMEOUT) {
+		struct hermes_debug_entry *e = 
+			&hw->dbuf[(hw->dbufp++) % HERMES_DEBUG_BUFSIZE];
+		e->bap = bap;
+		e->id = id;
+		e->offset = offset;
+		e->cycles = HERMES_BAP_BUSY_TIMEOUT - k;
+	}
+#endif
+
 	if (reg & HERMES_OFFSET_BUSY)
 		return -ETIMEDOUT;
 
@@ -339,7 +384,7 @@
 	hermes_write_reg(hw, oreg, offset);
 
 	/* Wait for the BAP to be ready */
-	k = BAP_BUSY_TIMEOUT;
+	k = HERMES_BAP_BUSY_TIMEOUT;
 	reg = hermes_read_reg(hw, oreg);
 	while ( (reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) {
 		k--;
@@ -373,7 +418,7 @@
 	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
 	int err = 0;
 
-	if (len % 2)
+	if ( (len < 0) || (len % 2) )
 		return -EINVAL;
 
 	err = hermes_bap_seek(hw, bap, id, offset);
@@ -399,7 +444,7 @@
 	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
 	int err = 0;
 
-	if (len % 2)
+	if ( (len < 0) || (len % 2) )
 		return -EINVAL;
 
 	err = hermes_bap_seek(hw, bap, id, offset);
@@ -427,12 +472,11 @@
 	int err = 0;
 	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
 	u16 rlength, rtype;
-	hermes_response_t resp;
 
-	if (bufsize % 2)
+	if ( (bufsize < 0) || (bufsize % 2) )
 		return -EINVAL;
 
-	err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, &resp);
+	err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL);
 	if (err)
 		goto out;
 
@@ -447,11 +491,14 @@
 		*length = rlength;
 
 	if (rtype != rid)
-		printk(KERN_WARNING "hermes_read_ltv(): rid  (0x%04x) does "
-		       "not match type (0x%04x)\n", rid, rtype);
+		printk(KERN_WARNING "hermes @ %s0x%lx: "
+		       "hermes_read_ltv(): rid  (0x%04x) does not match type (0x%04x)\n",
+		       IO_TYPE(hw), hw->iobase, rid, rtype);
 	if (HERMES_RECLEN_TO_BYTES(rlength) > bufsize)
-		printk(KERN_WARNING "hermes @ 0x%x: Truncating LTV record from %d to %d bytes. "
-		       "(rid=0x%04x, len=0x%04x)\n", hw->iobase,
+		printk(KERN_WARNING "hermes @ %s0x%lx: "
+		       "Truncating LTV record from %d to %d bytes. "
+		       "(rid=0x%04x, len=0x%04x)\n",
+		       IO_TYPE(hw), hw->iobase,
 		       HERMES_RECLEN_TO_BYTES(rlength), bufsize, rid, rlength);
 	
 	/* FIXME: we should read the min of the requested length and
@@ -467,7 +514,6 @@
 {
 	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
 	int err = 0;
-	hermes_response_t resp;
 	int count;
 	
 	DEBUG(3, "write_ltv(): bap=%d rid=0x%04x length=%d (value=0x%04x)\n",
@@ -485,7 +531,7 @@
 	hermes_write_words(hw, dreg, value, count);
 
 	err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, 
-				rid, &resp);
+				rid, NULL);
 
  out:
 	return err;
diff -Nru a/drivers/net/wireless/hermes.h b/drivers/net/wireless/hermes.h
--- a/drivers/net/wireless/hermes.h	Tue Apr 30 17:10:23 2002
+++ b/drivers/net/wireless/hermes.h	Tue Apr 30 17:10:23 2002
@@ -48,7 +48,6 @@
 #define		HERMES_PDA_LEN_MAX		(1024)	/* in bytes, from EK */
 #define		HERMES_SCANRESULT_MAX		(35)
 #define		HERMES_CHINFORESULT_MAX		(8)
-#define		HERMES_FRAME_LEN_MAX		(2304)
 #define		HERMES_MAX_MULTICAST		(16)
 #define		HERMES_MAGIC			(0x7d1f)
 
@@ -138,7 +137,7 @@
 
 /*--- Regulate Commands --------------------------*/
 #define		HERMES_CMD_NOTIFY		(0x0010)
-#define		HERMES_CMD_INQ			(0x0011)
+#define		HERMES_CMD_INQUIRE		(0x0011)
 
 /*--- Configure Commands --------------------------*/
 #define		HERMES_CMD_ACCESS		(0x0021)
@@ -150,126 +149,160 @@
 #define		HERMES_MONITOR_DISABLE		(0x000f)
 
 /*
- * Configuration RIDs
+ * Frame structures and constants
  */
 
-#define		HERMES_RID_CNF_PORTTYPE		(0xfc00)
-#define		HERMES_RID_CNF_MACADDR		(0xfc01)
-#define		HERMES_RID_CNF_DESIRED_SSID	(0xfc02)
-#define		HERMES_RID_CNF_CHANNEL		(0xfc03)
-#define		HERMES_RID_CNF_OWN_SSID		(0xfc04)
-#define		HERMES_RID_CNF_SYSTEM_SCALE	(0xfc06)
-#define		HERMES_RID_CNF_MAX_DATA_LEN	(0xfc07)
-#define		HERMES_RID_CNF_PM_ENABLE	(0xfc09)
-#define		HERMES_RID_CNF_PM_MCAST_RX	(0xfc0b)
-#define		HERMES_RID_CNF_PM_PERIOD	(0xfc0c)
-#define		HERMES_RID_CNF_PM_HOLDOVER	(0xfc0d)
-#define		HERMES_RID_CNF_NICKNAME		(0xfc0e)
-#define		HERMES_RID_CNF_WEP_ON		(0xfc20)
-#define		HERMES_RID_CNF_MWO_ROBUST	(0xfc25)
-#define		HERMES_RID_CNF_MULTICAST_LIST	(0xfc80)
-#define		HERMES_RID_CNF_CREATEIBSS	(0xfc81)
-#define		HERMES_RID_CNF_FRAG_THRESH	(0xfc82)
-#define		HERMES_RID_CNF_RTS_THRESH	(0xfc83)
-#define		HERMES_RID_CNF_TX_RATE_CTRL	(0xfc84)
-#define		HERMES_RID_CNF_PROMISCUOUS	(0xfc85)
-#define		HERMES_RID_CNF_KEYS		(0xfcb0)
-#define		HERMES_RID_CNF_TX_KEY		(0xfcb1)
-#define		HERMES_RID_CNF_TICKTIME		(0xfce0)
-
-#define		HERMES_RID_CNF_INTERSIL_WEP_ON	(0xfc28)
-#define		HERMES_RID_CNF_INTERSIL_TX_KEY	(0xfc23)
-#define		HERMES_RID_CNF_INTERSIL_KEY0	(0xfc24)
-#define		HERMES_RID_CNF_INTERSIL_KEY1	(0xfc25)
-#define		HERMES_RID_CNF_INTERSIL_KEY2	(0xfc26)
-#define		HERMES_RID_CNF_INTERSIL_KEY3	(0xfc27)
-#define		HERMES_RID_CNF_SYMBOL_MANDATORY_BSSID	(0xfc21)
-#define		HERMES_RID_CNF_SYMBOL_AUTH_TYPE		(0xfc2A)
-#define		HERMES_RID_CNF_SYMBOL_BASIC_RATES	(0xfc8A)
-#define		HERMES_RID_CNF_SYMBOL_PREAMBLE		(0xfc8C)
-
-/*
- * Information RIDs
- */
-#define		HERMES_RID_CHANNEL_LIST		(0xfd10)
-#define		HERMES_RID_STAIDENTITY		(0xfd20)
-#define		HERMES_RID_CURRENT_SSID		(0xfd41)
-#define		HERMES_RID_CURRENT_BSSID	(0xfd42)
-#define		HERMES_RID_COMMSQUALITY		(0xfd43)
-#define 	HERMES_RID_CURRENT_TX_RATE	(0xfd44)
-#define 	HERMES_RID_SHORT_RETRY_LIMIT	(0xfd48)
-#define 	HERMES_RID_LONG_RETRY_LIMIT	(0xfd49)
-#define 	HERMES_RID_MAX_TX_LIFETIME	(0xfd4A)
-#define		HERMES_RID_WEP_AVAIL		(0xfd4f)
-#define		HERMES_RID_CURRENT_CHANNEL	(0xfdc1)
-#define		HERMES_RID_DATARATES		(0xfdc6)
-#define		HERMES_RID_SYMBOL_SECONDARY_VER	(0xfd24)
-#define		HERMES_RID_SYMBOL_KEY_LENGTH	(0xfc2B)
+#define HERMES_DESCRIPTOR_OFFSET	0
+#define HERMES_802_11_OFFSET		(14)
+#define HERMES_802_3_OFFSET		(14+32)
+#define HERMES_802_2_OFFSET		(14+32+14)
 
-/*
- * Frame structures and constants
- */
+struct hermes_rx_descriptor {
+	u16 status;
+	u32 time;
+	u8 silence;
+	u8 signal;
+	u8 rate;
+	u8 rxflow;
+	u32 reserved;
+} __attribute__ ((packed));
+
+#define HERMES_RXSTAT_ERR		(0x0003)
+#define	HERMES_RXSTAT_BADCRC		(0x0001)
+#define	HERMES_RXSTAT_UNDECRYPTABLE	(0x0002)
+#define	HERMES_RXSTAT_MACPORT		(0x0700)
+#define	HERMES_RXSTAT_MSGTYPE		(0xE000)
+#define	HERMES_RXSTAT_1042		(0x2000)	/* RFC-1042 frame */
+#define	HERMES_RXSTAT_TUNNEL		(0x4000)	/* bridge-tunnel encoded frame */
+#define	HERMES_RXSTAT_WMP		(0x6000)	/* Wavelan-II Management Protocol frame */
 
-typedef struct hermes_frame_desc {
-	/* Hermes - i.e. little-endian byte-order */
+struct hermes_tx_descriptor {
 	u16 status;
-	u16 res1, res2;
-	u16 q_info;
-	u16 res3, res4;
-	u16 tx_ctl;
-} __attribute__ ((packed)) hermes_frame_desc_t;
-
-#define		HERMES_RXSTAT_ERR		(0x0003)
-#define		HERMES_RXSTAT_MACPORT		(0x0700)
-#define		HERMES_RXSTAT_MSGTYPE		(0xE000)
-
-#define		HERMES_RXSTAT_BADCRC		(0x0001)
-#define		HERMES_RXSTAT_UNDECRYPTABLE	(0x0002)
-
-/* RFC-1042 encoded frame */
-#define		HERMES_RXSTAT_1042		(0x2000)
-/* Bridge-tunnel encoded frame */
-#define		HERMES_RXSTAT_TUNNEL		(0x4000)
-/* Wavelan-II Management Protocol frame */
-#define		HERMES_RXSTAT_WMP		(0x6000)
+	u16 reserved1;
+	u16 reserved2;
+	u32 sw_support;
+	u8 retry_count;
+	u8 tx_rate;
+	u16 tx_control;	
+} __attribute__ ((packed));
+
+#define HERMES_TXSTAT_RETRYERR		(0x0001)
+#define HERMES_TXSTAT_AGEDERR		(0x0002)
+#define HERMES_TXSTAT_DISCON		(0x0004)
+#define HERMES_TXSTAT_FORMERR		(0x0008)
+
+#define HERMES_TXCTRL_TX_OK		(0x0002)	/* ?? interrupt on Tx complete */
+#define HERMES_TXCTRL_TX_EX		(0x0004)	/* ?? interrupt on Tx exception */
+#define HERMES_TXCTRL_802_11		(0x0008)	/* We supply 802.11 header */
+#define HERMES_TXCTRL_ALT_RTRY		(0x0020)
+
+/* Inquiry constants and data types */
+
+#define HERMES_INQ_TALLIES		(0xF100)
+#define HERMES_INQ_SCAN			(0xF101)
+#define HERMES_INQ_LINKSTATUS		(0xF200)
+
+struct hermes_tallies_frame {
+	u16 TxUnicastFrames;
+	u16 TxMulticastFrames;
+	u16 TxFragments;
+	u16 TxUnicastOctets;
+	u16 TxMulticastOctets;
+	u16 TxDeferredTransmissions;
+	u16 TxSingleRetryFrames;
+	u16 TxMultipleRetryFrames;
+	u16 TxRetryLimitExceeded;
+	u16 TxDiscards;
+	u16 RxUnicastFrames;
+	u16 RxMulticastFrames;
+	u16 RxFragments;
+	u16 RxUnicastOctets;
+	u16 RxMulticastOctets;
+	u16 RxFCSErrors;
+	u16 RxDiscards_NoBuffer;
+	u16 TxDiscardsWrongSA;
+	u16 RxWEPUndecryptable;
+	u16 RxMsgInMsgFragments;
+	u16 RxMsgInBadMsgFragments;
+	/* Those last are probably not available in very old firmwares */
+	u16 RxDiscards_WEPICVError;
+	u16 RxDiscards_WEPExcluded;
+} __attribute__ ((packed));
+
+/* Grabbed from wlan-ng - Thanks Mark... - Jean II
+ * This is the result of a scan inquiry command */
+/* Structure describing info about an Access Point */
+struct hermes_scan_apinfo {
+	u16 channel;		/* Channel where the AP sits */
+	u16 noise;		/* Noise level */
+	u16 level;		/* Signal level */
+	u8 bssid[ETH_ALEN];	/* MAC address of the Access Point */
+	u16 beacon_interv;	/* Beacon interval ? */
+	u16 capabilities;	/* Capabilities ? */
+	u8 essid[32];		/* ESSID of the network */
+	u8 rates[10];		/* Bit rate supported */
+	u16 proberesp_rate;	/* ???? */
+} __attribute__ ((packed));
+/* Container */
+struct hermes_scan_frame {
+	u16 rsvd;                   /* ??? */
+	u16 scanreason;             /* ??? */
+	struct hermes_scan_apinfo aps[35];        /* Scan result */
+} __attribute__ ((packed));
+
+// #define HERMES_DEBUG_BUFFER 1
+#define HERMES_DEBUG_BUFSIZE 4096
+struct hermes_debug_entry {
+	int bap;
+	u16 id, offset;
+	int cycles;
+};
 
 #ifdef __KERNEL__
 
+/* Timeouts */
+#define HERMES_BAP_BUSY_TIMEOUT (500) /* In iterations of ~1us */
+
 /* Basic control structure */
 typedef struct hermes {
-	uint iobase;
+	ulong iobase;
+	int io_space; /* 1 if we IO-mapped IO, 0 for memory-mapped IO? */
+#define HERMES_IO	1
+#define HERMES_MEM	0
+	int reg_spacing;
+#define HERMES_16BIT_REGSPACING	0
+#define HERMES_32BIT_REGSPACING	1
 
 	u16 inten; /* Which interrupts should be enabled? */
+
+#ifdef HERMES_DEBUG_BUFFER
+	struct hermes_debug_entry dbuf[HERMES_DEBUG_BUFSIZE];
+	unsigned long dbufp;
+	unsigned long profile[HERMES_BAP_BUSY_TIMEOUT+1];
+#endif
 } hermes_t;
 
 typedef struct hermes_response {
 	u16 status, resp0, resp1, resp2;
 } hermes_response_t;
 
-/* "ID" structure - used for ESSID and station nickname */
-typedef struct hermes_id {
-	u16 len;
-	u16 val[16];
-} __attribute__ ((packed)) hermes_id_t;
-
-typedef struct hermes_multicast {
-	u8 addr[HERMES_MAX_MULTICAST][ETH_ALEN];
-} __attribute__ ((packed)) hermes_multicast_t;
-
 /* Register access convenience macros */
-#define hermes_read_reg(hw, off) (inw((hw)->iobase + (off)))
-#define hermes_write_reg(hw, off, val) (outw_p((val), (hw)->iobase + (off)))
+#define hermes_read_reg(hw, off) ((hw)->io_space ? \
+	inw((hw)->iobase + ( (off) << (hw)->reg_spacing )) : \
+	readw((hw)->iobase + ( (off) << (hw)->reg_spacing )))
+#define hermes_write_reg(hw, off, val) ((hw)->io_space ? \
+	outw_p((val), (hw)->iobase + ( (off) << (hw)->reg_spacing )) : \
+	writew((val), (hw)->iobase + ( (off) << (hw)->reg_spacing )))
 
 #define hermes_read_regn(hw, name) (hermes_read_reg((hw), HERMES_##name))
 #define hermes_write_regn(hw, name, val) (hermes_write_reg((hw), HERMES_##name, (val)))
 
 /* Function prototypes */
-void hermes_struct_init(hermes_t *hw, uint io);
+void hermes_struct_init(hermes_t *hw, ulong address, int io_space, int reg_spacing);
 int hermes_reset(hermes_t *hw);
 int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, hermes_response_t *resp);
 int hermes_allocate(hermes_t *hw, u16 size, u16 *fid);
 
-int hermes_bap_seek(hermes_t *hw, int bap, u16 id, u16 offset);
 int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len,
 		       u16 id, u16 offset);
 int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
@@ -300,26 +333,62 @@
 
 static inline int hermes_enable_port(hermes_t *hw, int port)
 {
-	hermes_response_t resp;
-
 	return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8),
-				 0, &resp);
+				 0, NULL);
 }
 
 static inline int hermes_disable_port(hermes_t *hw, int port)
 {
-	hermes_response_t resp;
+	return hermes_docmd_wait(hw, HERMES_CMD_DISABLE | (port << 8), 
+				 0, NULL);
+}
 
-	return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8), 
-				 0, &resp);
+/* Initiate an INQUIRE command (tallies or scan).  The result will come as an
+ * information frame in __orinoco_ev_info() */
+static inline int hermes_inquire(hermes_t *hw, u16 rid)
+{
+	return hermes_docmd_wait(hw, HERMES_CMD_INQUIRE, rid, NULL);
 }
 
 #define HERMES_BYTES_TO_RECLEN(n) ( ((n) % 2) ? (((n)+1)/2)+1 : ((n)/2)+1 )
 #define HERMES_RECLEN_TO_BYTES(n) ( ((n)-1) * 2 )
 
 /* Note that for the next two, the count is in 16-bit words, not bytes */
-#define hermes_read_words(hw, off, buf, count) (insw((hw)->iobase + (off), (buf), (count)))
-#define hermes_write_words(hw, off, buf, count) (outsw((hw)->iobase + (off), (buf), (count)))
+static inline void hermes_read_words(struct hermes *hw, int off, void *buf, int count)
+{
+	off = off << hw->reg_spacing;;
+
+	if (hw->io_space) {
+		insw(hw->iobase + off, buf, count);
+	} else {
+		int i;
+		u16 *p;
+
+		/* This need to *not* byteswap (like insw()) but
+		 * readw() does byteswap hence the conversion */
+		for (i = 0, p = buf; i < count; i++) {
+			*p++ = cpu_to_le16(readw(hw->iobase + off));
+		}
+	}
+}
+
+static inline void hermes_write_words(struct hermes *hw, int off, const void *buf, int count)
+{
+	off = off << hw->reg_spacing;;
+
+	if (hw->io_space) {
+		outsw(hw->iobase + off, buf, count);
+	} else {
+		int i;
+		const u16 *p;
+
+		/* This need to *not* byteswap (like outsw()) but
+		 * writew() does byteswap hence the conversion */
+		for (i = 0, p = buf; i < count; i++) {
+			writew(le16_to_cpu(*p++), hw->iobase + off);
+		}
+	}
+}
 
 #define HERMES_READ_RECORD(hw, bap, rid, buf) \
 	(hermes_read_ltv((hw),(bap),(rid), sizeof(*buf), NULL, (buf)))
diff -Nru a/drivers/net/wireless/hermes_rid.h b/drivers/net/wireless/hermes_rid.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/wireless/hermes_rid.h	Tue Apr 30 17:10:25 2002
@@ -0,0 +1,153 @@
+#ifndef _HERMES_RID_H
+#define _HERMES_RID_H
+
+/*
+ * Configuration RIDs
+ */
+#define HERMES_RID_CNFPORTTYPE			0xFC00	/* used */
+#define HERMES_RID_CNFOWNMACADDR		0xFC01	/* used */
+#define HERMES_RID_CNFDESIREDSSID		0xFC02	/* used */
+#define HERMES_RID_CNFOWNCHANNEL		0xFC03	/* used */
+#define HERMES_RID_CNFOWNSSID			0xFC04	/* used */
+#define HERMES_RID_CNFOWNATIMWINDOW		0xFC05
+#define HERMES_RID_CNFSYSTEMSCALE		0xFC06	/* used */
+#define HERMES_RID_CNFMAXDATALEN		0xFC07
+#define HERMES_RID_CNFWDSADDRESS		0xFC08
+#define HERMES_RID_CNFPMENABLED			0xFC09	/* used */
+#define HERMES_RID_CNFPMEPS			0xFC0A
+#define HERMES_RID_CNFMULTICASTRECEIVE		0xFC0B	/* used */
+#define HERMES_RID_CNFMAXSLEEPDURATION		0xFC0C	/* used */
+#define HERMES_RID_CNFPMHOLDOVERDURATION	0xFC0D	/* used */
+#define HERMES_RID_CNFOWNNAME			0xFC0E	/* used */
+#define HERMES_RID_CNFOWNDTIMPERIOD		0xFC10
+#define HERMES_RID_CNFWDSADDRESS1		0xFC11
+#define HERMES_RID_CNFWDSADDRESS2		0xFC12
+#define HERMES_RID_CNFWDSADDRESS3		0xFC13
+#define HERMES_RID_CNFWDSADDRESS4		0xFC14
+#define HERMES_RID_CNFWDSADDRESS5		0xFC15
+#define HERMES_RID_CNFWDSADDRESS6		0xFC16
+#define HERMES_RID_CNFMULTICASTPMBUFFERING	0xFC17
+#define HERMES_RID_CNFWEPENABLED_AGERE		0xFC20	/* used */
+#define HERMES_RID_CNFMANDATORYBSSID_SYMBOL	0xFC21
+#define HERMES_RID_CNFWEPDEFAULTKEYID		0xFC23	/* used */
+#define HERMES_RID_CNFDEFAULTKEY0		0xFC24	/* used */
+#define HERMES_RID_CNFDEFAULTKEY1		0xFC25	/* used */
+#define HERMES_RID_CNFMWOROBUST_AGERE		0xFC25	/* used */
+#define HERMES_RID_CNFDEFAULTKEY2		0xFC26	/* used */
+#define HERMES_RID_CNFDEFAULTKEY3		0xFC27	/* used */
+#define HERMES_RID_CNFWEPFLAGS_INTERSIL		0xFC28	/* used */
+#define HERMES_RID_CNFWEPKEYMAPPINGTABLE	0xFC29
+#define HERMES_RID_CNFAUTHENTICATION		0xFC2A	/* used */
+#define HERMES_RID_CNFMAXASSOCSTA		0xFC2B
+#define	HERMES_RID_CNFKEYLENGTH_SYMBOL		0xFC2B
+#define HERMES_RID_CNFTXCONTROL			0xFC2C
+#define HERMES_RID_CNFROAMINGMODE		0xFC2D
+#define HERMES_RID_CNFHOSTAUTHENTICATION	0xFC2E
+#define HERMES_RID_CNFRCVCRCERROR		0xFC30
+#define HERMES_RID_CNFMMLIFE			0xFC31
+#define HERMES_RID_CNFALTRETRYCOUNT		0xFC32
+#define HERMES_RID_CNFBEACONINT			0xFC33
+#define HERMES_RID_CNFAPPCFINFO			0xFC34
+#define HERMES_RID_CNFSTAPCFINFO		0xFC35
+#define HERMES_RID_CNFPRIORITYQUSAGE		0xFC37
+#define HERMES_RID_CNFTIMCTRL			0xFC40
+#define HERMES_RID_CNFTHIRTY2TALLY		0xFC42
+#define HERMES_RID_CNFENHSECURITY		0xFC43
+#define HERMES_RID_CNFGROUPADDRESSES		0xFC80	/* used */
+#define HERMES_RID_CNFCREATEIBSS		0xFC81	/* used */
+#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD	0xFC82	/* used */
+#define HERMES_RID_CNFRTSTHRESHOLD		0xFC83	/* used */
+#define HERMES_RID_CNFTXRATECONTROL		0xFC84	/* used */
+#define HERMES_RID_CNFPROMISCUOUSMODE		0xFC85	/* used */
+#define HERMES_RID_CNFBASICRATES_SYMBOL		0xFC8A
+#define HERMES_RID_CNFPREAMBLE_SYMBOL		0xFC8C	/* used */
+#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD0	0xFC90
+#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD1	0xFC91
+#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD2	0xFC92
+#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD3	0xFC93
+#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD4	0xFC94
+#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD5	0xFC95
+#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD6	0xFC96
+#define HERMES_RID_CNFRTSTHRESHOLD0		0xFC97
+#define HERMES_RID_CNFRTSTHRESHOLD1		0xFC98
+#define HERMES_RID_CNFRTSTHRESHOLD2		0xFC99
+#define HERMES_RID_CNFRTSTHRESHOLD3		0xFC9A
+#define HERMES_RID_CNFRTSTHRESHOLD4		0xFC9B
+#define HERMES_RID_CNFRTSTHRESHOLD5		0xFC9C
+#define HERMES_RID_CNFRTSTHRESHOLD6		0xFC9D
+#define HERMES_RID_CNFSHORTPREAMBLE		0xFCB0
+#define HERMES_RID_CNFWEPKEYS_AGERE		0xFCB0	/* used */
+#define HERMES_RID_CNFEXCLUDELONGPREAMBLE	0xFCB1
+#define HERMES_RID_CNFTXKEY_AGERE		0xFCB1	/* used */
+#define HERMES_RID_CNFAUTHENTICATIONRSPTO	0xFCB2
+#define HERMES_RID_CNFBASICRATES		0xFCB3
+#define HERMES_RID_CNFSUPPORTEDRATES		0xFCB4
+#define HERMES_RID_CNFTICKTIME			0xFCE0	/* used */
+#define HERMES_RID_CNFSCANREQUEST		0xFCE1
+#define HERMES_RID_CNFJOINREQUEST		0xFCE2
+#define HERMES_RID_CNFAUTHENTICATESTATION	0xFCE3
+#define HERMES_RID_CNFCHANNELINFOREQUEST	0xFCE4
+
+/*
+ * Information RIDs
+ */
+#define HERMES_RID_MAXLOADTIME			0xFD00
+#define HERMES_RID_DOWNLOADBUFFER		0xFD01
+#define HERMES_RID_PRIID			0xFD02
+#define HERMES_RID_PRISUPRANGE			0xFD03
+#define HERMES_RID_CFIACTRANGES			0xFD04
+#define HERMES_RID_NICSERNUM			0xFD0A
+#define HERMES_RID_NICID			0xFD0B
+#define HERMES_RID_MFISUPRANGE			0xFD0C
+#define HERMES_RID_CFISUPRANGE			0xFD0D
+#define HERMES_RID_CHANNELLIST			0xFD10	/* used */
+#define HERMES_RID_REGULATORYDOMAINS		0xFD11
+#define HERMES_RID_TEMPTYPE			0xFD12
+#define HERMES_RID_CIS				0xFD13
+#define HERMES_RID_STAID			0xFD20	/* used */
+#define HERMES_RID_STASUPRANGE			0xFD21
+#define HERMES_RID_MFIACTRANGES			0xFD22
+#define HERMES_RID_CFIACTRANGES2		0xFD23
+#define HERMES_RID_SECONDARYVERSION_SYMBOL	0xFD24	/* used */
+#define HERMES_RID_PORTSTATUS			0xFD40
+#define HERMES_RID_CURRENTSSID			0xFD41	/* used */
+#define HERMES_RID_CURRENTBSSID			0xFD42	/* used */
+#define HERMES_RID_COMMSQUALITY			0xFD43	/* used */
+#define HERMES_RID_CURRENTTXRATE		0xFD44	/* used */
+#define HERMES_RID_CURRENTBEACONINTERVAL	0xFD45
+#define HERMES_RID_CURRENTSCALETHRESHOLDS	0xFD46
+#define HERMES_RID_PROTOCOLRSPTIME		0xFD47
+#define HERMES_RID_SHORTRETRYLIMIT		0xFD48	/* used */
+#define HERMES_RID_LONGRETRYLIMIT		0xFD49	/* used */
+#define HERMES_RID_MAXTRANSMITLIFETIME		0xFD4A	/* used */
+#define HERMES_RID_MAXRECEIVELIFETIME		0xFD4B
+#define HERMES_RID_CFPOLLABLE			0xFD4C
+#define HERMES_RID_AUTHENTICATIONALGORITHMS	0xFD4D
+#define HERMES_RID_PRIVACYOPTIONIMPLEMENTED	0xFD4F
+#define HERMES_RID_CURRENTTXRATE1		0xFD80
+#define HERMES_RID_CURRENTTXRATE2		0xFD81
+#define HERMES_RID_CURRENTTXRATE3		0xFD82
+#define HERMES_RID_CURRENTTXRATE4		0xFD83
+#define HERMES_RID_CURRENTTXRATE5		0xFD84
+#define HERMES_RID_CURRENTTXRATE6		0xFD85
+#define HERMES_RID_OWNMACADDR			0xFD86
+#define HERMES_RID_SCANRESULTSTABLE		0xFD88
+#define HERMES_RID_PHYTYPE			0xFDC0
+#define HERMES_RID_CURRENTCHANNEL		0xFDC1	/* used */
+#define HERMES_RID_CURRENTPOWERSTATE		0xFDC2
+#define HERMES_RID_CCAMODE			0xFDC3
+#define HERMES_RID_SUPPORTEDDATARATES		0xFDC6	/* used */
+#define HERMES_RID_BUILDSEQ			0xFFFE
+#define HERMES_RID_FWID				0xFFFF
+
+/* "ID" structure - used for ESSID and station nickname */
+struct hermes_idstring {
+	u16 len;
+	u16 val[16];
+} __attribute__ ((packed));
+
+typedef struct hermes_multicast {
+	u8 addr[HERMES_MAX_MULTICAST][ETH_ALEN];
+} __attribute__ ((packed)) hermes_multicast_t;
+
+#endif
diff -Nru a/drivers/net/wireless/ieee802_11.h b/drivers/net/wireless/ieee802_11.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/wireless/ieee802_11.h	Tue Apr 30 17:10:25 2002
@@ -0,0 +1,73 @@
+#ifndef _IEEE802_11_H
+#define _IEEE802_11_H
+
+#define IEEE802_11_DATA_LEN		2304
+/* Actually, the standard seems to be inconsistent about what the
+   maximum frame size really is.  S6.2.1.1.2 says 2304 octets, but the
+   figure in section 7.1.2 says 2312 octects. */
+#define IEEE802_11_HLEN			30
+#define IEEE802_11_FRAME_LEN		(IEEE802_11_DATA_LEN + IEEE802_11_HLEN)
+
+struct ieee802_11_hdr {
+	u16 frame_ctl;
+	u16 duration_id;
+	u8 addr1[ETH_ALEN];
+	u8 addr2[ETH_ALEN];
+	u8 addr3[ETH_ALEN];
+	u16 seq_ctl;
+	u8 addr4[ETH_ALEN];
+} __attribute__ ((packed));
+
+/* Frame control field constants */
+#define IEEE802_11_FCTL_VERS		0x0002
+#define IEEE802_11_FCTL_FTYPE		0x000c
+#define IEEE802_11_FCTL_STYPE		0x00f0
+#define IEEE802_11_FCTL_TODS		0x0100
+#define IEEE802_11_FCTL_FROMDS		0x0200
+#define IEEE802_11_FCTL_MOREFRAGS	0x0400
+#define IEEE802_11_FCTL_RETRY		0x0800
+#define IEEE802_11_FCTL_PM		0x1000
+#define IEEE802_11_FCTL_MOREDATA	0x2000
+#define IEEE802_11_FCTL_WEP		0x4000
+#define IEEE802_11_FCTL_ORDER		0x8000
+
+#define IEEE802_11_FTYPE_MGMT		0x0000
+#define IEEE802_11_FTYPE_CTL		0x0004
+#define IEEE802_11_FTYPE_DATA		0x0008
+
+/* management */
+#define IEEE802_11_STYPE_ASSOC_REQ	0x0000
+#define IEEE802_11_STYPE_ASSOC_RESP 	0x0010
+#define IEEE802_11_STYPE_REASSOC_REQ	0x0020
+#define IEEE802_11_STYPE_REASSOC_RESP	0x0030
+#define IEEE802_11_STYPE_PROBE_REQ	0x0040
+#define IEEE802_11_STYPE_PROBE_RESP	0x0050
+#define IEEE802_11_STYPE_BEACON		0x0080
+#define IEEE802_11_STYPE_ATIM		0x0090
+#define IEEE802_11_STYPE_DISASSOC	0x00A0
+#define IEEE802_11_STYPE_AUTH		0x00B0
+#define IEEE802_11_STYPE_DEAUTH		0x00C0
+
+/* control */
+#define IEEE802_11_STYPE_PSPOLL		0x00A0
+#define IEEE802_11_STYPE_RTS		0x00B0
+#define IEEE802_11_STYPE_CTS		0x00C0
+#define IEEE802_11_STYPE_ACK		0x00D0
+#define IEEE802_11_STYPE_CFEND		0x00E0
+#define IEEE802_11_STYPE_CFENDACK	0x00F0
+
+/* data */
+#define IEEE802_11_STYPE_DATA		0x0000
+#define IEEE802_11_STYPE_DATA_CFACK	0x0010
+#define IEEE802_11_STYPE_DATA_CFPOLL	0x0020
+#define IEEE802_11_STYPE_DATA_CFACKPOLL	0x0030
+#define IEEE802_11_STYPE_NULLFUNC	0x0040
+#define IEEE802_11_STYPE_CFACK		0x0050
+#define IEEE802_11_STYPE_CFPOLL		0x0060
+#define IEEE802_11_STYPE_CFACKPOLL	0x0070
+
+#define IEEE802_11_SCTL_FRAG		0x000F
+#define IEEE802_11_SCTL_SEQ		0xFFF0
+
+#endif /* _IEEE802_11_H */
+
diff -Nru a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
--- a/drivers/net/wireless/orinoco.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/net/wireless/orinoco.c	Tue Apr 30 17:10:25 2002
@@ -1,11 +1,7 @@
-/* orinoco.c 0.08a	- (formerly known as dldwd_cs.c and orinoco_cs.c)
+/* orinoco.c 0.11a	- (formerly known as dldwd_cs.c and orinoco_cs.c)
  *
- * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such
- * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/
- * EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others).
- * It should also be usable on various Prism II based cards such as the
- * Linksys, D-Link and Farallon Skyline. It should also work on Symbol
- * cards such as the 3Com AirConnect and Ericsson WLAN.
+ * A driver for Hermes or Prism 2 chipset based PCMCIA wireless
+ * adaptors, with Lucent/Agere, Intersil or Symbol firmware.
  *
  * Copyright (C) 2000 David Gibson, Linuxcare Australia <hermes@gibson.dropbear.id.au>
  *	With some help from :
@@ -41,12 +37,9 @@
  * deleting the provisions above and replace them with the notice and
  * other provisions required by the GPL.  If you do not delete the
  * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.
- */
+ * under either the MPL or the GPL.  */
 
 /*
- * Tentative changelog...
- *
  * v0.01 -> v0.02 - 21/3/2001 - Jean II
  *	o Allow to use regular ethX device name instead of dldwdX
  *	o Warning on IBSS with ESSID=any for firmware 6.06
@@ -197,18 +190,106 @@
  *	o Fixed bad bug in WEP key handling on Intersil and Symbol firmware,
  *	  which led to an instant crash on big-endian machines.
  *
- * TODO - Jean II
- *	o inline functions (lots of candidate, need to reorder code)
- *	o Test PrismII/Symbol cards & firmware versions
- *	o Mini-PCI support (some people have reported success - JII)
- *	o Find and kill remaining Tx timeout problems
- */
+ * v0.08a -> v0.08b - 20/11/2001 - David Gibson
+ *	o Lots of cleanup and bugfixes in orinoco_plx.c
+ *	o Cleanup to handling of Tx rate setting.
+ *	o Removed support for old encapsulation method.
+ *	o Removed old "dldwd" names.
+ *	o Split RID constants into a new file hermes_rid.h
+ *	o Renamed RID constants to match linux-wlan-ng and prism2.o
+ *	o Bugfixes in hermes.c
+ *	o Poke the PLX's INTCSR register, so it actually starts
+ *	  generating interrupts.  These cards might actually work now.
+ *	o Update to wireless extensions v12 (Jean II)
+ *	o Support for tallies and inquire command (Jean II)
+ *	o Airport updates for newer PPC kernels (BenH)
+ *
+ * v0.08b -> v0.09 - 21/12/2001 - David Gibson
+ *	o Some new PCI IDs for PLX cards.
+ *	o Removed broken attempt to do ALLMULTI reception.  Just use
+ *	  promiscuous mode instead
+ *	o Preliminary work for list-AP (Jean II)
+ *	o Airport updates from (BenH)
+ *	o Eliminated racy hw_ready stuff
+ *	o Fixed generation of fake events in irq handler.  This should
+ *	  finally kill the EIO problems (Jean II & dgibson)
+ *	o Fixed breakage of bitrate set/get on Agere firmware (Jean II)
+ *
+ * v0.09 -> v0.09a - 2/1/2002 - David Gibson
+ *	o Fixed stupid mistake in multicast list handling, triggering
+ *	  a BUG()
+ *
+ * v0.09a -> v0.09b - 16/1/2002 - David Gibson
+ *	o Fixed even stupider mistake in new interrupt handling, which
+ *	  seriously broke things on big-endian machines.
+ *	o Removed a bunch of redundant includes and exports.
+ *	o Removed a redundant MOD_{INC,DEC}_USE_COUNT pair in airport.c
+ *	o Don't attempt to do hardware level multicast reception on
+ *	  Intersil firmware, just go promisc instead.
+ *	o Typo fixed in hermes_issue_cmd()
+ *	o Eliminated WIRELESS_SPY #ifdefs
+ *	o Status code reported on Tx exceptions
+ *	o Moved netif_wake_queue() from ALLOC interrupts to TX and TXEXC
+ *	  interrupts, which should fix the timeouts we're seeing.
+ *
+ * v0.09b -> v0.10 - 25 Feb 2002 - David Gibson
+ *	o Removed nested structures used for header parsing, so the
+ *	  driver should now work without hackery on ARM
+ *	o Fix for WEP handling on Intersil (Hawk Newton)
+ *	o Eliminated the /proc/hermes/ethXX/regs debugging file.  It
+ *	  was never very useful.
+ *	o Make Rx errors less noisy.
+ *
+ * v0.10 -> v0.11 - 5 Apr Mar 2002 - David Gibson
+ *	o Laid the groundwork in hermes.[ch] for devices which map
+ *	  into PCI memory space rather than IO space.
+ *	o Fixed bug in multicast handling (cleared multicast list when
+ *	  leaving promiscuous mode).
+ *	o Relegated Tx error messages to debug.
+ *	o Cleaned up / corrected handling of allocation lengths.
+ *	o Set OWNSSID in IBSS mode for WinXP interoperability (jimc).
+ *	o Change to using alloc_etherdev() for structure allocations. 
+ *	o Check for and drop undersized packets.
+ *	o Fixed a race in stopping/waking the queue.  This should fix
+ *	  the timeout problems (Pavel Roskin)
+ *	o Reverted to netif_wake_queue() on the ALLOC event.
+ *	o Fixes for recent Symbol firmwares which lack AP density
+ *	  (Pavel Roskin).
+ *
+ * v0.11 -> v0.11a - 29 Apr 2002 - David Gibson
+ *	o Handle different register spacing, necessary for Prism 2.5
+ *	  PCI adaptors (Steve Hill).
+ *	o Cleaned up initialization of card structures in orinoco_cs
+ *	  and airport.  Removed card->priv field.
+ *	o Make response structure optional for hermes_docmd_wait()
+ *	  Pavel Roskin)
+ *	o Added PCI id for Nortel emobility to orinoco_plx.c.
+ *	o Cleanup to handling of Symbol's allocation bug. (Pavel Roskin)
+ *	o Cleanups to firmware capability detection.
+ *	o Arrange for orinoco_pci.c to override firmware detection.
+ *	  We should be able to support the PCI Intersil cards now.
+ *	o Cleanup handling of reset_cor and hard_reset (Pavel Roskin).
+ *	o Remove erroneous use of USER_BAP in the TxExc handler (Jouni
+ *	  Malinen).
+ *	o Makefile changes for better integration into David Hinds
+ *	  pcmcia-cs package.
+ *
+ * TODO
+ *	o Re-assess our encapsulation detection strategy
+ *	o Handle de-encapsulation within network layer, provide 802.11
+ *	  headers
+ *	o Fix possible races in SPY handling.
+ *	o Disconnect wireless extensions from fundamental configuration.
+ *
+ *	o Convert /proc debugging stuff to seqfile
+ *	o Use multiple Tx buffers */
 /* Notes on locking:
  *
  * The basic principle of operation is that everything except the
  * interrupt handler is serialized through a single spinlock in the
- * dldwd_priv_t structure, using dldwd_lock() and
- * dldwd_unlock() (which in turn use spin_lock_bh() and spin_unlock_bh()).
+ * struct orinoco_private structure, using orinoco_lock() and
+ * orinoco_unlock() (which in turn use spin_lock_bh() and
+ * spin_unlock_bh()).
  *
  * The kernel's IRQ handling stuff ensures that the interrupt handler
  * does not re-enter itself. The interrupt handler is written such
@@ -216,16 +297,17 @@
  * that the Rx path uses one of the Hermes chipset's BAPs while
  * everything else uses the other.
  *
- * Actually, the current updating of the statistics from the interrupt
- * handler is unsafe.  However all it can do is perturb the
- * packet/byte counts slightly, so we just put up with it.  We could
- * fix this to use atomic types, but it's probably not worth it.
+ * Actually, strictly speaking, the updating of the statistics from
+ * the interrupt handler isn't safe without a lock.  However the worst
+ * that can happen is that we perturb the packet/byte counts slightly.
+ * We could fix this to use atomic types, but it's probably not worth
+ * it.
  *
  * The big exception is that that we don't want the irq handler
  * running when we actually reset or shut down the card, because
  * strange things might happen (probably the worst would be one packet
  * of garbage, but you can't be too careful). For this we use
- * __dldwd_stop_irqs() which will set a flag to disable the interrupt
+ * __orinoco_stop_irqs() which will set a flag to disable the interrupt
  * handler, and wait for any outstanding instances of the handler to
  * complete. THIS WILL LOSE INTERRUPTS! so it shouldn't be used except
  * for resets, where losing a few interrupts is acceptable. */
@@ -245,220 +327,217 @@
 #include <asm/io.h>
 #include <asm/system.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/etherdevice.h>
 #include <linux/wireless.h>
 #include <linux/list.h>
 
-#include <pcmcia/version.h>
-#include <pcmcia/cs_types.h>
-#include <pcmcia/cs.h>
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ds.h>
-#include <pcmcia/bus_ops.h>
-
 #include "hermes.h"
+#include "hermes_rid.h"
 #include "orinoco.h"
+#include "ieee802_11.h"
+
+/* Wireless extensions backwards compatibility */
+#ifndef SIOCIWFIRSTPRIV
+#define SIOCIWFIRSTPRIV		SIOCDEVPRIVATE
+#endif /* SIOCIWFIRSTPRIV */
+
+/* We do this this way to avoid ifdefs in the actual code */
+#ifdef WIRELESS_SPY
+#define SPY_NUMBER(priv)	(priv->spy_number)
+#else
+#define SPY_NUMBER(priv)	0
+#endif /* WIRELESS_SPY */
 
-static char version[] __initdata = "orinoco.c 0.08a (David Gibson <hermes@gibson.dropbear.id.au> and others)";
+static char version[] __initdata = "orinoco.c 0.11a (David Gibson <hermes@gibson.dropbear.id.au> and others)";
 MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>");
 MODULE_DESCRIPTION("Driver for Lucent Orinoco, Prism II based and similar wireless cards");
+#ifdef MODULE_LICENSE
 MODULE_LICENSE("Dual MPL/GPL");
+#endif
 
 /* Level of debugging. Used in the macros in orinoco.h */
 #ifdef ORINOCO_DEBUG
-int dldwd_debug = ORINOCO_DEBUG;
-MODULE_PARM(dldwd_debug, "i");
+int orinoco_debug = ORINOCO_DEBUG;
+MODULE_PARM(orinoco_debug, "i");
+EXPORT_SYMBOL(orinoco_debug);
 #endif
 
-int use_old_encaps = 0;
-MODULE_PARM(use_old_encaps, "i");
+#define ORINOCO_MIN_MTU		256
+#define ORINOCO_MAX_MTU		(IEEE802_11_DATA_LEN - ENCAPS_OVERHEAD)
 
 #define SYMBOL_MAX_VER_LEN	(14)
+#define USER_BAP		0
+#define IRQ_BAP			1
+#define MAX_IRQLOOPS_PER_IRQ	10
+#define MAX_IRQLOOPS_PER_JIFFY	(20000/HZ)	/* Based on a guestimate of how many events the
+						   device can legitimately generate */
+#define SMALL_KEY_SIZE		5
+#define LARGE_KEY_SIZE		13
+#define TX_NICBUF_SIZE_BUG	1585		/* Bug in Symbol firmware */
+
+#define DUMMY_FID		0xFFFF
+
+/*#define MAX_MULTICAST(priv)	(priv->firmware_type == FIRMWARE_TYPE_AGERE ? \
+  HERMES_MAX_MULTICAST : 0)*/
+#define MAX_MULTICAST(priv)	(HERMES_MAX_MULTICAST)
+
+/********************************************************************/
+/* Data tables                                                      */
+/********************************************************************/
 
+/* The frequency of each channel in MHz */
 const long channel_frequency[] = {
 	2412, 2417, 2422, 2427, 2432, 2437, 2442,
 	2447, 2452, 2457, 2462, 2467, 2472, 2484
 };
-
 #define NUM_CHANNELS ( sizeof(channel_frequency) / sizeof(channel_frequency[0]) )
 
-/* This tables gives the actual meanings of the bitrate IDs returned by the firmware.
-   It gives the rate in halfMb/s, negative indicates auto mode */
-const int rate_list[] = { 0, 2, 4, -22, 11, 22, -4, -11, 0, 0, 0, 0};
-
-#define NUM_RATES (sizeof(rate_list) / sizeof(rate_list[0]))
-
-struct p80211_hdr {
-	u16 frame_ctl;
-	u16 duration_id;
-	u8 addr1[ETH_ALEN];
-	u8 addr2[ETH_ALEN];
-	u8 addr3[ETH_ALEN];
-	u16 seq_ctl;
-	u8 addr4[ETH_ALEN];
-	u16 data_len;
-} __attribute__ ((packed));
-
-/* Frame control field constants */
-#define DLDWD_FCTL_VERS			0x0002
-#define DLDWD_FCTL_FTYPE		0x000c
-#define DLDWD_FCTL_STYPE		0x00f0
-#define DLDWD_FCTL_TODS			0x0100
-#define DLDWD_FCTL_FROMDS		0x0200
-#define DLDWD_FCTL_MOREFRAGS		0x0400
-#define DLDWD_FCTL_RETRY		0x0800
-#define DLDWD_FCTL_PM			0x1000
-#define DLDWD_FCTL_MOREDATA		0x2000
-#define DLDWD_FCTL_WEP			0x4000
-#define DLDWD_FCTL_ORDER		0x8000
-
-#define DLDWD_FTYPE_MGMT		0x0000
-#define DLDWD_FTYPE_CTL			0x0004
-#define DLDWD_FTYPE_DATA		0x0008
+/* This tables gives the actual meanings of the bitrate IDs returned by the firmware. */
+struct {
+	int bitrate; /* in 100s of kilbits */
+	int automatic;
+	u16 agere_txratectrl;
+	u16 intersil_txratectrl;
+} bitrate_table[] = {
+	{110, 1,  3, 15}, /* Entry 0 is the default */
+	{10,  0,  1,  1},
+	{10,  1,  1,  1},
+	{20,  0,  2,  2},
+	{20,  1,  6,  3},
+	{55, 0,  4,  4},
+	{55, 1,  7,  7},
+	{110, 0,  5,  8},
+};
+#define BITRATE_TABLE_SIZE (sizeof(bitrate_table) / sizeof(bitrate_table[0]))
 
-struct p8022_hdr {
+struct header_struct {
+	/* 802.3 */
+	u8 dest[ETH_ALEN];
+	u8 src[ETH_ALEN];
+	u16 len;
+	/* 802.2 */
 	u8 dsap;
 	u8 ssap;
 	u8 ctrl;
+	/* SNAP */
 	u8 oui[3];
-} __attribute__ ((packed));
-
-struct dldwd_frame_hdr {
-	hermes_frame_desc_t desc;
-	struct p80211_hdr p80211;
-	struct ethhdr p8023;
-	struct p8022_hdr p8022;
 	u16 ethertype;
 } __attribute__ ((packed));
 
-#define P8023_OFFSET		(sizeof(hermes_frame_desc_t) + \
-				sizeof(struct p80211_hdr))
-#define ENCAPS_OVERHEAD		(sizeof(struct p8022_hdr) + 2)
-
-/* 802.2 LLL header SNAP used for SNAP encapsulation over 802.11 */
-struct p8022_hdr encaps_hdr = {
-	0xaa, 0xaa, 0x03, {0x00, 0x00, 0x00}
-};
-
-struct p8022_hdr old_encaps_hdr = {
-	0xaa, 0xaa, 0x03, {0x00, 0x00, 0xf8}
-};
+/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
+u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
 
-/* How many times to retry if we get an EIO reading the BAP in the Rx path */
-#define RX_EIO_RETRY		10
-
-typedef struct dldwd_commsqual {
-	u16 qual, signal, noise;
-} __attribute__ ((packed)) dldwd_commsqual_t;
+#define ENCAPS_OVERHEAD		(sizeof(encaps_hdr) + 2)
 
 /*
  * Function prototypes
  */
 
-static void dldwd_stat_gather(struct net_device *dev,
+static void orinoco_stat_gather(struct net_device *dev,
 			      struct sk_buff *skb,
-			      struct dldwd_frame_hdr *hdr);
+			      struct hermes_rx_descriptor *desc);
 
-static struct net_device_stats *dldwd_get_stats(struct net_device *dev);
-static struct iw_statistics *dldwd_get_wireless_stats(struct net_device *dev);
+static struct net_device_stats *orinoco_get_stats(struct net_device *dev);
+static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev);
 
 /* Hardware control routines */
 
-static int __dldwd_hw_reset(dldwd_priv_t *priv);
-static int __dldwd_hw_setup_wep(dldwd_priv_t *priv);
-static int dldwd_hw_get_bssid(dldwd_priv_t *priv, char buf[ETH_ALEN]);
-static int dldwd_hw_get_essid(dldwd_priv_t *priv, int *active, char buf[IW_ESSID_MAX_SIZE+1]);
-static long dldwd_hw_get_freq(dldwd_priv_t *priv);
-static int dldwd_hw_get_bitratelist(dldwd_priv_t *priv, int *numrates,
+static int __orinoco_hw_set_bitrate(struct orinoco_private *priv);
+static int __orinoco_hw_setup_wep(struct orinoco_private *priv);
+static int orinoco_hw_get_bssid(struct orinoco_private *priv, char buf[ETH_ALEN]);
+static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
+			      char buf[IW_ESSID_MAX_SIZE+1]);
+static long orinoco_hw_get_freq(struct orinoco_private *priv);
+static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, int *numrates,
 				    s32 *rates, int max);
+static void __orinoco_set_multicast_list(struct net_device *dev);
 
 /* Interrupt handling routines */
-static void __dldwd_ev_tick(dldwd_priv_t *priv, hermes_t *hw);
-static void __dldwd_ev_wterr(dldwd_priv_t *priv, hermes_t *hw);
-static void __dldwd_ev_infdrop(dldwd_priv_t *priv, hermes_t *hw);
-static void __dldwd_ev_info(dldwd_priv_t *priv, hermes_t *hw);
-static void __dldwd_ev_rx(dldwd_priv_t *priv, hermes_t *hw);
-static void __dldwd_ev_txexc(dldwd_priv_t *priv, hermes_t *hw);
-static void __dldwd_ev_tx(dldwd_priv_t *priv, hermes_t *hw);
-static void __dldwd_ev_alloc(dldwd_priv_t *priv, hermes_t *hw);
-
-static int dldwd_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq);
-static int dldwd_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq);
-static int dldwd_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq);
-static int dldwd_ioctl_setessid(struct net_device *dev, struct iw_point *erq);
-static int dldwd_ioctl_getessid(struct net_device *dev, struct iw_point *erq);
-static int dldwd_ioctl_setnick(struct net_device *dev, struct iw_point *nrq);
-static int dldwd_ioctl_getnick(struct net_device *dev, struct iw_point *nrq);
-static int dldwd_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq);
-static int dldwd_ioctl_getsens(struct net_device *dev, struct iw_param *srq);
-static int dldwd_ioctl_setsens(struct net_device *dev, struct iw_param *srq);
-static int dldwd_ioctl_setrts(struct net_device *dev, struct iw_param *rrq);
-static int dldwd_ioctl_setfrag(struct net_device *dev, struct iw_param *frq);
-static int dldwd_ioctl_getfrag(struct net_device *dev, struct iw_param *frq);
-static int dldwd_ioctl_setrate(struct net_device *dev, struct iw_param *frq);
-static int dldwd_ioctl_getrate(struct net_device *dev, struct iw_param *frq);
-static int dldwd_ioctl_setpower(struct net_device *dev, struct iw_param *prq);
-static int dldwd_ioctl_getpower(struct net_device *dev, struct iw_param *prq);
-static int dldwd_ioctl_setport3(struct net_device *dev, struct iwreq *wrq);
-static int dldwd_ioctl_getport3(struct net_device *dev, struct iwreq *wrq);
-static void __dldwd_set_multicast_list(struct net_device *dev);
+static void __orinoco_ev_tick(struct orinoco_private *priv, hermes_t *hw);
+static void __orinoco_ev_wterr(struct orinoco_private *priv, hermes_t *hw);
+static void __orinoco_ev_infdrop(struct orinoco_private *priv, hermes_t *hw);
+static void __orinoco_ev_info(struct orinoco_private *priv, hermes_t *hw);
+static void __orinoco_ev_rx(struct orinoco_private *priv, hermes_t *hw);
+static void __orinoco_ev_txexc(struct orinoco_private *priv, hermes_t *hw);
+static void __orinoco_ev_tx(struct orinoco_private *priv, hermes_t *hw);
+static void __orinoco_ev_alloc(struct orinoco_private *priv, hermes_t *hw);
+
+static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq);
+static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq);
+static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq);
+static int orinoco_ioctl_setessid(struct net_device *dev, struct iw_point *erq);
+static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq);
+static int orinoco_ioctl_setnick(struct net_device *dev, struct iw_point *nrq);
+static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq);
+static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq);
+static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq);
+static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq);
+static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq);
+static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq);
+static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq);
+static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *frq);
+static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *frq);
+static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq);
+static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq);
+static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq);
+static int orinoco_ioctl_getport3(struct net_device *dev, struct iwreq *wrq);
 
 /* /proc debugging stuff */
-static int dldwd_proc_init(void);
-static void dldwd_proc_cleanup(void);
+static int orinoco_proc_init(void);
+static void orinoco_proc_cleanup(void);
 
 /*
  * Inline functions
  */
 static inline void
-dldwd_lock(dldwd_priv_t *priv)
+orinoco_lock(struct orinoco_private *priv)
 {
 	spin_lock_bh(&priv->lock);
 }
 
 static inline void
-dldwd_unlock(dldwd_priv_t *priv)
+orinoco_unlock(struct orinoco_private *priv)
 {
 	spin_unlock_bh(&priv->lock);
 }
 
 static inline int
-dldwd_irqs_allowed(dldwd_priv_t *priv)
+orinoco_irqs_allowed(struct orinoco_private *priv)
 {
-	return test_bit(DLDWD_STATE_DOIRQ, &priv->state);
+	return test_bit(ORINOCO_STATE_DOIRQ, &priv->state);
 }
 
 static inline void
-__dldwd_stop_irqs(dldwd_priv_t *priv)
+__orinoco_stop_irqs(struct orinoco_private *priv)
 {
 	hermes_t *hw = &priv->hw;
 
 	hermes_set_irqmask(hw, 0);
-	clear_bit(DLDWD_STATE_DOIRQ, &priv->state);
-	while (test_bit(DLDWD_STATE_INIRQ, &priv->state))
+	clear_bit(ORINOCO_STATE_DOIRQ, &priv->state);
+	while (test_bit(ORINOCO_STATE_INIRQ, &priv->state))
 		;
 }
 
 static inline void
-__dldwd_start_irqs(dldwd_priv_t *priv, u16 irqmask)
+__orinoco_start_irqs(struct orinoco_private *priv, u16 irqmask)
 {
 	hermes_t *hw = &priv->hw;
 
-	TRACE_ENTER(priv->ndev.name);
+	TRACE_ENTER(priv->ndev->name);
 
-	__cli();
-	set_bit(DLDWD_STATE_DOIRQ, &priv->state);
+	__cli(); /* FIXME: is this necessary? */
+	set_bit(ORINOCO_STATE_DOIRQ, &priv->state);
 	hermes_set_irqmask(hw, irqmask);
 	__sti();
 
-	TRACE_EXIT(priv->ndev.name);
+	TRACE_EXIT(priv->ndev->name);
 }
 
 static inline void
-set_port_type(dldwd_priv_t *priv)
+set_port_type(struct orinoco_private *priv)
 {
 	switch (priv->iw_mode) {
 	case IW_MODE_INFRA:
@@ -476,103 +555,90 @@
 		break;
 	default:
 		printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n",
-		       priv->ndev.name);
+		       priv->ndev->name);
 	}
 }
 
-extern void
-dldwd_set_multicast_list(struct net_device *dev)
+static inline int
+is_snap(struct header_struct *hdr)
+{
+	return (hdr->dsap == 0xAA) && (hdr->ssap == 0xAA) && (hdr->ctrl == 0x3);
+}
+
+static void
+orinoco_set_multicast_list(struct net_device *dev)
 {
-	dldwd_priv_t *priv = dev->priv;
+	struct orinoco_private *priv = dev->priv;
 
-	dldwd_lock(priv);
-	__dldwd_set_multicast_list(dev);
-	dldwd_unlock(priv);
+	orinoco_lock(priv);
+	__orinoco_set_multicast_list(dev);
+	orinoco_unlock(priv);
 }
 
 /*
  * Hardware control routines
  */
 
-static int
-__dldwd_hw_reset(dldwd_priv_t *priv)
-{
-	hermes_t *hw = &priv->hw;
-	int err;
-
-	if (! priv->broken_reset)
-		return hermes_reset(hw);
-	else {
-		hw->inten = 0;
-		hermes_write_regn(hw, INTEN, 0);
-		err = hermes_disable_port(hw, 0);
-		hermes_write_regn(hw, EVACK, 0xffff);
-		return err;
-	}
-}
-
 void
-dldwd_shutdown(dldwd_priv_t *priv)
+orinoco_shutdown(struct orinoco_private *priv)
 {
-/* 	hermes_t *hw = &priv->hw; */
 	int err = 0;
 
-	TRACE_ENTER(priv->ndev.name);
+	TRACE_ENTER(priv->ndev->name);
 
-	dldwd_lock(priv);
-	__dldwd_stop_irqs(priv);
+	orinoco_lock(priv);
+	__orinoco_stop_irqs(priv);
 
-	err = __dldwd_hw_reset(priv);
+	err = hermes_reset(&priv->hw);
 	if (err && err != -ENODEV) /* If the card is gone, we don't care about shutting it down */
-		printk(KERN_ERR "%s: Error %d shutting down Hermes chipset\n", priv->ndev.name, err);
+		printk(KERN_ERR "%s: Error %d shutting down Hermes chipset\n", priv->ndev->name, err);
 
-	dldwd_unlock(priv);
+	orinoco_unlock(priv);
 
-	TRACE_EXIT(priv->ndev.name);
+	TRACE_EXIT(priv->ndev->name);
 }
 
 int
-dldwd_reset(dldwd_priv_t *priv)
+orinoco_reset(struct orinoco_private *priv)
 {
-	struct net_device *dev = &priv->ndev;
+	struct net_device *dev = priv->ndev;
 	hermes_t *hw = &priv->hw;
 	int err = 0;
-	hermes_id_t idbuf;
-	int frame_size;
+	struct hermes_idstring idbuf;
 
-	TRACE_ENTER(priv->ndev.name);
+	TRACE_ENTER(priv->ndev->name);
 
 	/* Stop other people bothering us */
-	dldwd_lock(priv);
-	__dldwd_stop_irqs(priv);
+	orinoco_lock(priv);
+	__orinoco_stop_irqs(priv);
 
 	/* Check if we need a card reset */
-	if((priv->need_card_reset) && (priv->card_reset_handler != NULL))
-		priv->card_reset_handler(priv);
+	if (priv->hard_reset)
+		priv->hard_reset(priv);
 
 	/* Do standard firmware reset if we can */
-	err = __dldwd_hw_reset(priv);
+	err = hermes_reset(hw);
 	if (err)
 		goto out;
 
-	frame_size = TX_NICBUF_SIZE;
-	/* This stupid bug is present in Intel firmware 1.10, and
-	 * may be fixed in later firmwares - Jean II */
-	if(priv->broken_allocate)
-		frame_size = TX_NICBUF_SIZE_BUG;
-	err = hermes_allocate(hw, frame_size, &priv->txfid);
-	if (err)
-		goto out;
+	err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
+	if (err == -EIO) {
+		/* Try workaround for old Symbol firmware bug */
+		priv->nicbuf_size = TX_NICBUF_SIZE_BUG;
+		err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
+		if (err)
+			goto out;
+	}
 
 	/* Now set up all the parameters on the card */
 	
 	/* Set up the link mode */
 	
-	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PORTTYPE, priv->port_type);
+	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE, priv->port_type);
 	if (err)
 		goto out;
 	if (priv->has_ibss) {
-		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_CREATEIBSS,
+		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFCREATEIBSS,
 					   priv->allow_ibss);
 		if (err)
 			goto out;
@@ -586,21 +652,16 @@
 		}
 	}
 
-	/* Set up encryption */
-	if (priv->has_wep) {
-		err = __dldwd_hw_setup_wep(priv);
-		if (err) {
-			printk(KERN_ERR "%s: Error %d activating WEP.\n",
-			       dev->name, err);
-			goto out;
-		}
-	}
-
 	/* Set the desired ESSID */
 	idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
 	memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
-	err = hermes_write_ltv(hw, USER_BAP, (priv->port_type == 3) ?
-			       HERMES_RID_CNF_OWN_SSID : HERMES_RID_CNF_DESIRED_SSID,
+	/* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */
+	err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID,
+			       HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
+			       &idbuf);
+	if (err)
+		goto out;
+	err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID,
 			       HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
 			       &idbuf);
 	if (err)
@@ -609,58 +670,65 @@
 	/* Set the station name */
 	idbuf.len = cpu_to_le16(strlen(priv->nick));
 	memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val));
-	err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNF_NICKNAME,
+	err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
 			       HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2),
 			       &idbuf);
 	if (err)
 		goto out;
 
 	/* Set the channel/frequency */
-	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_CHANNEL, priv->channel);
+	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFOWNCHANNEL, priv->channel);
 	if (err)
 		goto out;
 
 	/* Set AP density */
-	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, priv->ap_density);
-	if (err)
-		goto out;
+	if (priv->has_sensitivity) {
+		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE,
+					   priv->ap_density);
+		if (err)
+			priv->has_sensitivity = 0;
+	}
 
 	/* Set RTS threshold */
-	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_RTS_THRESH, priv->rts_thresh);
+	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, priv->rts_thresh);
 	if (err)
 		goto out;
 
 	/* Set fragmentation threshold or MWO robustness */
 	if (priv->has_mwo)
 		err = hermes_write_wordrec(hw, USER_BAP,
-					   HERMES_RID_CNF_MWO_ROBUST, priv->mwo_robust);
+					   HERMES_RID_CNFMWOROBUST_AGERE,
+					   priv->mwo_robust);
 	else
 		err = hermes_write_wordrec(hw, USER_BAP,
-					   HERMES_RID_CNF_FRAG_THRESH, priv->frag_thresh);
+					   HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
+					   priv->frag_thresh);
 	if (err)
 		goto out;
 
 	/* Set bitrate */
-	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_RATE_CTRL,
-				   priv->tx_rate_ctrl);
+	err = __orinoco_hw_set_bitrate(priv);
 	if (err)
 		goto out;
 
 	/* Set power management */
 	if (priv->has_pm) {
-		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_ENABLE,
+		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPMENABLED,
 					   priv->pm_on);
 		if (err)
 			goto out;
-		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_MCAST_RX,
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNFMULTICASTRECEIVE,
 					   priv->pm_mcast);
 		if (err)
 			goto out;
-		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD,
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNFMAXSLEEPDURATION,
 					   priv->pm_period);
 		if (err)
 			goto out;
-		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER,
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNFPMHOLDOVERDURATION,
 					   priv->pm_timeout);
 		if (err)
 			goto out;
@@ -668,7 +736,8 @@
 
 	/* Set preamble - only for Symbol so far... */
 	if (priv->has_preamble) {
-		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_PREAMBLE,
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNFPREAMBLE_SYMBOL,
 					   priv->preamble);
 		if (err) {
 			printk(KERN_WARNING "%s: Can't set preamble!\n", dev->name);
@@ -676,50 +745,100 @@
 		}
 	}
 
+	/* Set up encryption */
+	if (priv->has_wep) {
+		err = __orinoco_hw_setup_wep(priv);
+		if (err) {
+			printk(KERN_ERR "%s: Error %d activating WEP.\n",
+			       dev->name, err);
+			goto out;
+		}
+	}
+
 	/* Set promiscuity / multicast*/
 	priv->promiscuous = 0;
-	priv->allmulti = 0;
 	priv->mc_count = 0;
-	__dldwd_set_multicast_list(dev);
-	
-	err = hermes_enable_port(hw, DLDWD_MACPORT);
-	if (err)
-		goto out;
+	__orinoco_set_multicast_list(dev);
 	
-	__dldwd_start_irqs(priv, HERMES_EV_RX | HERMES_EV_ALLOC |
+	__orinoco_start_irqs(priv, HERMES_EV_RX | HERMES_EV_ALLOC |
 			   HERMES_EV_TX | HERMES_EV_TXEXC |
 			   HERMES_EV_WTERR | HERMES_EV_INFO |
 			   HERMES_EV_INFDROP);
 
+	err = hermes_enable_port(hw, 0);
+	if (err)
+		goto out;
+
  out:
-	dldwd_unlock(priv);
+	orinoco_unlock(priv);
 
-	TRACE_EXIT(priv->ndev.name);
+	TRACE_EXIT(priv->ndev->name);
 
 	return err;
 }
 
-static int __dldwd_hw_setup_wep(dldwd_priv_t *priv)
+static int __orinoco_hw_set_bitrate(struct orinoco_private *priv)
+{
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+
+	TRACE_ENTER(priv->ndev->name);
+
+	if (priv->bitratemode >= BITRATE_TABLE_SIZE) {
+		printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n",
+		       priv->ndev->name, priv->bitratemode);
+		return -EINVAL;
+	}
+
+	switch (priv->firmware_type) {
+	case FIRMWARE_TYPE_AGERE:
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNFTXRATECONTROL,
+					   bitrate_table[priv->bitratemode].agere_txratectrl);
+		break;
+	case FIRMWARE_TYPE_INTERSIL:
+	case FIRMWARE_TYPE_SYMBOL:
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNFTXRATECONTROL,
+					   bitrate_table[priv->bitratemode].intersil_txratectrl);
+		break;
+	default:
+		BUG();
+	}
+
+	TRACE_EXIT(priv->ndev->name);
+
+	return err;
+}
+
+
+static int __orinoco_hw_setup_wep(struct orinoco_private *priv)
 {
 	hermes_t *hw = &priv->hw;
 	int err = 0;
 	int	master_wep_flag;
 	int	auth_flag;
 
-	TRACE_ENTER(priv->ndev.name);
+	TRACE_ENTER(priv->ndev->name);
 
 	switch (priv->firmware_type) {
-	case FIRMWARE_TYPE_LUCENT: /* Lucent style WEP */
+	case FIRMWARE_TYPE_AGERE: /* Agere style WEP */
 		if (priv->wep_on) {
-			err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_KEY, priv->tx_key);
+			err = hermes_write_wordrec(hw, USER_BAP,
+						   HERMES_RID_CNFTXKEY_AGERE,
+						   priv->tx_key);
 			if (err)
 				return err;
 			
-			err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNF_KEYS, &priv->keys);
+			err = HERMES_WRITE_RECORD(hw, USER_BAP,
+						  HERMES_RID_CNFWEPKEYS_AGERE,
+						  &priv->keys);
 			if (err)
 				return err;
 		}
-		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_WEP_ON, priv->wep_on);
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNFWEPENABLED_AGERE,
+					   priv->wep_on);
 		if (err)
 			return err;
 		break;
@@ -728,26 +847,24 @@
 	case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */
 		master_wep_flag = 0;		/* Off */
 		if (priv->wep_on) {
-/*  			int keylen; */
+			int keylen;
 			int i;
 
 			/* Fudge around firmware weirdness */
-/*  			keylen = priv->keys[priv->tx_key].len; */
-
+			keylen = le16_to_cpu(priv->keys[priv->tx_key].len);
+			
 			/* Write all 4 keys */
-			for(i = 0; i < MAX_KEYS; i++) {
-				int keylen = le16_to_cpu(priv->keys[i].len);
-
+			for(i = 0; i < ORINOCO_MAX_KEYS; i++) {
+/*  				int keylen = le16_to_cpu(priv->keys[i].len); */
+				
 				if (keylen > LARGE_KEY_SIZE) {
 					printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n",
-					       priv->ndev.name, i, keylen);
+					       priv->ndev->name, i, keylen);
 					return -E2BIG;
 				}
 
-				printk("About to write key %d, keylen=%d\n",
-				       i, keylen);				     
 				err = hermes_write_ltv(hw, USER_BAP,
-						       HERMES_RID_CNF_INTERSIL_KEY0 + i,
+						       HERMES_RID_CNFDEFAULTKEY0 + i,
 						       HERMES_BYTES_TO_RECLEN(keylen),
 						       priv->keys[i].data);
 				if (err)
@@ -755,39 +872,35 @@
 			}
 
 			/* Write the index of the key used in transmission */
-			err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_INTERSIL_TX_KEY,
+			err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFWEPDEFAULTKEYID,
 						   priv->tx_key);
 			if (err)
 				return err;
-
-			/* Authentication is where Intersil and Symbol
-			 * firmware differ... */
-			if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) {
-				/* Symbol cards : set the authentication :
-				 * 0 -> no encryption, 1 -> open,
-				 * 2 -> shared key
-				 * 3 -> shared key 128 -> AP only */
-				if(priv->wep_restrict)
-					auth_flag = 2;
-				else
-					auth_flag = 1;
-				err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_AUTH_TYPE, auth_flag);
-				if (err)
-					return err;
-				/* Master WEP setting is always 3 */
+			
+			if (priv->wep_restrict) {
+				auth_flag = 2;
 				master_wep_flag = 3;
 			} else {
-				/* Prism2 card : we need to modify master
-				 * WEP setting */
-				if(priv->wep_restrict)
-					master_wep_flag = 3;
-				else
-					master_wep_flag = 1;
+				/* Authentication is where Intersil and Symbol
+				 * firmware differ... */
+				auth_flag = 1;
+				if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)
+					master_wep_flag = 3; /* Symbol */ 
+				else 
+					master_wep_flag = 1; /* Intersil */
 			}
+
+
+			err = hermes_write_wordrec(hw, USER_BAP,
+						   HERMES_RID_CNFAUTHENTICATION, auth_flag);
+			if (err)
+				return err;
 		}
 		
 		/* Master WEP setting : on/off */
-		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_INTERSIL_WEP_ON, master_wep_flag);
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNFWEPFLAGS_INTERSIL,
+					   master_wep_flag);
 		if (err)
 			return err;	
 
@@ -796,58 +909,58 @@
 	default:
 		if (priv->wep_on) {
 			printk(KERN_ERR "%s: WEP enabled, although not supported!\n",
-			       priv->ndev.name);
+			       priv->ndev->name);
 			return -EINVAL;
 		}
 	}
 
-	TRACE_EXIT(priv->ndev.name);
+	TRACE_EXIT(priv->ndev->name);
 
 	return 0;
 }
 
-static int dldwd_hw_get_bssid(dldwd_priv_t *priv, char buf[ETH_ALEN])
+static int orinoco_hw_get_bssid(struct orinoco_private *priv, char buf[ETH_ALEN])
 {
 	hermes_t *hw = &priv->hw;
 	int err = 0;
 
-	dldwd_lock(priv);
+	orinoco_lock(priv);
 
-	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_BSSID,
+	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
 			      ETH_ALEN, NULL, buf);
 
-	dldwd_unlock(priv);
+	orinoco_unlock(priv);
 
 	return err;
 }
 
-static int dldwd_hw_get_essid(dldwd_priv_t *priv, int *active,
+static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
 			      char buf[IW_ESSID_MAX_SIZE+1])
 {
 	hermes_t *hw = &priv->hw;
 	int err = 0;
-	hermes_id_t essidbuf;
+	struct hermes_idstring essidbuf;
 	char *p = (char *)(&essidbuf.val);
 	int len;
 
-	TRACE_ENTER(priv->ndev.name);
+	TRACE_ENTER(priv->ndev->name);
 
-	dldwd_lock(priv);
+	orinoco_lock(priv);
 
 	if (strlen(priv->desired_essid) > 0) {
 		/* We read the desired SSID from the hardware rather
 		   than from priv->desired_essid, just in case the
 		   firmware is allowed to change it on us. I'm not
 		   sure about this */
-		/* My guess is that the OWN_SSID should always be whatever
+		/* My guess is that the OWNSSID should always be whatever
 		 * we set to the card, whereas CURRENT_SSID is the one that
 		 * may change... - Jean II */
 		u16 rid;
 
 		*active = 1;
 
-		rid = (priv->port_type == 3) ? HERMES_RID_CNF_OWN_SSID :
-			HERMES_RID_CNF_DESIRED_SSID;
+		rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID :
+			HERMES_RID_CNFDESIREDSSID;
 		
 		err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf),
 				      NULL, &essidbuf);
@@ -856,7 +969,7 @@
 	} else {
 		*active = 0;
 
-		err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_SSID,
+		err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID,
 				      sizeof(essidbuf), NULL, &essidbuf);
 		if (err)
 			goto fail_unlock;
@@ -864,19 +977,19 @@
 
 	len = le16_to_cpu(essidbuf.len);
 
-	memset(buf, 0, sizeof(buf));
+	memset(buf, 0, IW_ESSID_MAX_SIZE+1);
 	memcpy(buf, p, len);
 	buf[len] = '\0';
 
  fail_unlock:
-	dldwd_unlock(priv);
+	orinoco_unlock(priv);
 
-	TRACE_EXIT(priv->ndev.name);
+	TRACE_EXIT(priv->ndev->name);
 
 	return err;       
 }
 
-static long dldwd_hw_get_freq(dldwd_priv_t *priv)
+static long orinoco_hw_get_freq(struct orinoco_private *priv)
 {
 	
 	hermes_t *hw = &priv->hw;
@@ -884,14 +997,14 @@
 	u16 channel;
 	long freq = 0;
 
-	dldwd_lock(priv);
+	orinoco_lock(priv);
 	
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_CHANNEL, &channel);
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL, &channel);
 	if (err)
 		goto out;
 
 	if ( (channel < 1) || (channel > NUM_CHANNELS) ) {
-		struct net_device *dev = &priv->ndev;
+		struct net_device *dev = priv->ndev;
 
 		printk(KERN_WARNING "%s: Channel out of range (%d)!\n", dev->name, channel);
 		err = -EBUSY;
@@ -901,27 +1014,27 @@
 	freq = channel_frequency[channel-1] * 100000;
 
  out:
-	dldwd_unlock(priv);
+	orinoco_unlock(priv);
 
 	if (err > 0)
 		err = -EBUSY;
 	return err ? err : freq;
 }
 
-static int dldwd_hw_get_bitratelist(dldwd_priv_t *priv, int *numrates,
+static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, int *numrates,
 				    s32 *rates, int max)
 {
 	hermes_t *hw = &priv->hw;
-	hermes_id_t list;
+	struct hermes_idstring list;
 	unsigned char *p = (unsigned char *)&list.val;
 	int err = 0;
 	int num;
 	int i;
 
-	dldwd_lock(priv);
-	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_DATARATES, sizeof(list),
-			      NULL, &list);
-	dldwd_unlock(priv);
+	orinoco_lock(priv);
+	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES,
+			      sizeof(list), NULL, &list);
+	orinoco_unlock(priv);
 
 	if (err)
 		return err;
@@ -937,19 +1050,20 @@
 	return 0;
 }
 
+#if 0
 #ifndef ORINOCO_DEBUG
-static inline void show_rx_frame(struct dldwd_frame_hdr *frame) {}
+static inline void show_rx_frame(struct orinoco_rxframe_hdr *frame) {}
 #else
-static void show_rx_frame(struct dldwd_frame_hdr *frame)
+static void show_rx_frame(struct orinoco_rxframe_hdr *frame)
 {
 	printk(KERN_DEBUG "RX descriptor:\n");
 	printk(KERN_DEBUG "  status      = 0x%04x\n", frame->desc.status);
-	printk(KERN_DEBUG "  res1        = 0x%04x\n", frame->desc.res1);
-	printk(KERN_DEBUG "  res2        = 0x%04x\n", frame->desc.res2);
-	printk(KERN_DEBUG "  q_info      = 0x%04x\n", frame->desc.q_info);
-	printk(KERN_DEBUG "  res3        = 0x%04x\n", frame->desc.res3);
-	printk(KERN_DEBUG "  res4        = 0x%04x\n", frame->desc.res4);
-	printk(KERN_DEBUG "  tx_ctl      = 0x%04x\n", frame->desc.tx_ctl);
+	printk(KERN_DEBUG "  time        = 0x%08x\n", frame->desc.time);
+	printk(KERN_DEBUG "  silence     = 0x%02x\n", frame->desc.silence);
+	printk(KERN_DEBUG "  signal      = 0x%02x\n", frame->desc.signal);
+	printk(KERN_DEBUG "  rate        = 0x%02x\n", frame->desc.rate);
+	printk(KERN_DEBUG "  rxflow      = 0x%02x\n", frame->desc.rxflow);
+	printk(KERN_DEBUG "  reserved    = 0x%08x\n", frame->desc.reserved);
 
 	printk(KERN_DEBUG "IEEE 802.11 header:\n");
 	printk(KERN_DEBUG "  frame_ctl   = 0x%04x\n",
@@ -997,182 +1111,246 @@
 	printk(KERN_DEBUG "  ethertype  = 0x%04x\n", frame->ethertype);
 }
 #endif
+#endif
 
 /*
  * Interrupt handler
  */
-void dldwd_interrupt(int irq, void * dev_id, struct pt_regs *regs)
+void orinoco_interrupt(int irq, void * dev_id, struct pt_regs *regs)
 {
-	dldwd_priv_t *priv = (dldwd_priv_t *) dev_id;
+	struct orinoco_private *priv = (struct orinoco_private *) dev_id;
 	hermes_t *hw = &priv->hw;
-	struct net_device *dev = &priv->ndev;
-	int count = IRQ_LOOP_MAX;
+	struct net_device *dev = priv->ndev;
+	int count = MAX_IRQLOOPS_PER_IRQ;
 	u16 evstat, events;
-	static int old_time = 0, timecount = 0; /* Eugh, revolting hack for now */
+	/* These are used to detect a runaway interrupt situation */
+	/* If we get more than MAX_IRQLOOPS_PER_JIFFY iterations in a jiffy,
+	 * we panic and shut down the hardware */
+	static int last_irq_jiffy = 0; /* jiffies value the last time we were called */
+	static int loops_this_jiffy = 0;
 
-	if (test_and_set_bit(DLDWD_STATE_INIRQ, &priv->state))
+	if (test_and_set_bit(ORINOCO_STATE_INIRQ, &priv->state))
 		BUG();
 
-	if (! dldwd_irqs_allowed(priv)) {
-		clear_bit(DLDWD_STATE_INIRQ, &priv->state);
+	if (! orinoco_irqs_allowed(priv)) {
+		clear_bit(ORINOCO_STATE_INIRQ, &priv->state);
 		return;
 	}
 
-	DEBUG(3, "%s: dldwd_interrupt()\n", priv->ndev.name);
+	DEBUG(3, "%s: orinoco_interrupt()\n", priv->ndev->name);
+
+	evstat = hermes_read_regn(hw, EVSTAT);
+	events = evstat & hw->inten;
+	
+/*  	if (! events) { */
+/*  		printk(KERN_WARNING "%s: Null event\n", dev->name); */
+/*  	} */
 
-	while (1) {
-		if (jiffies != old_time)
-			timecount = 0;
-		if ( (++timecount > 50) || (! count--) ) {
+	if (jiffies != last_irq_jiffy)
+		loops_this_jiffy = 0;
+	last_irq_jiffy = jiffies;
+
+	while (events && count--) {
+		DEBUG(3, "__orinoco_interrupt(): count=%d EVSTAT=0x%04x\n",
+		      count, evstat);
+		
+		if (++loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY) {
 			printk(KERN_CRIT "%s: IRQ handler is looping too \
 much! Shutting down.\n",
 			       dev->name);
 			/* Perform an emergency shutdown */
-			clear_bit(DLDWD_STATE_DOIRQ, &priv->state);
+			clear_bit(ORINOCO_STATE_DOIRQ, &priv->state);
 			hermes_set_irqmask(hw, 0);
 			break;
 		}
 
-		evstat = hermes_read_regn(hw, EVSTAT);
-		DEBUG(3, "__dldwd_interrupt(): count=%d EVSTAT=0x%04x inten=0x%04x\n",
-		      count, evstat, hw->inten);
-
-		events = evstat & hw->inten;
-
-		if (! events) {
-			if (netif_queue_stopped(dev)) {
-				/* There seems to be a firmware bug which
-				   sometimes causes the card to give an
-				   interrupt with no event set, when there
-				   sould be a Tx completed event. */
-				DEBUG(3, "%s: Interrupt with no event (ALLOCFID=0x%04x)\n",
-				      dev->name, (int)hermes_read_regn(hw, ALLOCFID));
-				events = HERMES_EV_TX | HERMES_EV_ALLOC;
-			} else /* Nothing's happening, we're done */
-				break;
-		}
-
 		/* Check the card hasn't been removed */
 		if (! hermes_present(hw)) {
-			DEBUG(0, "dldwd_interrupt(): card removed\n");
+			DEBUG(0, "orinoco_interrupt(): card removed\n");
 			break;
 		}
 
 		if (events & HERMES_EV_TICK)
-			__dldwd_ev_tick(priv, hw);
+			__orinoco_ev_tick(priv, hw);
 		if (events & HERMES_EV_WTERR)
-			__dldwd_ev_wterr(priv, hw);
+			__orinoco_ev_wterr(priv, hw);
 		if (events & HERMES_EV_INFDROP)
-			__dldwd_ev_infdrop(priv, hw);
+			__orinoco_ev_infdrop(priv, hw);
 		if (events & HERMES_EV_INFO)
-			__dldwd_ev_info(priv, hw);
+			__orinoco_ev_info(priv, hw);
 		if (events & HERMES_EV_RX)
-			__dldwd_ev_rx(priv, hw);
+			__orinoco_ev_rx(priv, hw);
 		if (events & HERMES_EV_TXEXC)
-			__dldwd_ev_txexc(priv, hw);
+			__orinoco_ev_txexc(priv, hw);
 		if (events & HERMES_EV_TX)
-			__dldwd_ev_tx(priv, hw);
+			__orinoco_ev_tx(priv, hw);
 		if (events & HERMES_EV_ALLOC)
-			__dldwd_ev_alloc(priv, hw);
+			__orinoco_ev_alloc(priv, hw);
 		
 		hermes_write_regn(hw, EVACK, events);
-	}
 
-	clear_bit(DLDWD_STATE_INIRQ, &priv->state);
+		evstat = hermes_read_regn(hw, EVSTAT);
+		events = evstat & hw->inten;
+	};
+
+	clear_bit(ORINOCO_STATE_INIRQ, &priv->state);
 }
 
-static void __dldwd_ev_tick(dldwd_priv_t *priv, hermes_t *hw)
+static void __orinoco_ev_tick(struct orinoco_private *priv, hermes_t *hw)
 {
-	printk(KERN_DEBUG "%s: TICK\n", priv->ndev.name);
+	printk(KERN_DEBUG "%s: TICK\n", priv->ndev->name);
 }
 
-static void __dldwd_ev_wterr(dldwd_priv_t *priv, hermes_t *hw)
+static void __orinoco_ev_wterr(struct orinoco_private *priv, hermes_t *hw)
 {
 	/* This seems to happen a fair bit under load, but ignoring it
 	   seems to work fine...*/
 	DEBUG(1, "%s: MAC controller error (WTERR). Ignoring.\n",
-	      priv->ndev.name);
+	      priv->ndev->name);
 }
 
-static void __dldwd_ev_infdrop(dldwd_priv_t *priv, hermes_t *hw)
+static void __orinoco_ev_infdrop(struct orinoco_private *priv, hermes_t *hw)
 {
-	printk(KERN_WARNING "%s: Information frame lost.\n", priv->ndev.name);
+	printk(KERN_WARNING "%s: Information frame lost.\n", priv->ndev->name);
 }
 
-static void __dldwd_ev_info(dldwd_priv_t *priv, hermes_t *hw)
+static void __orinoco_ev_info(struct orinoco_private *priv, hermes_t *hw)
 {
-	DEBUG(3, "%s: Information frame received.\n", priv->ndev.name);
-	/* We don't actually do anything about it - we assume the MAC
-	   controller can deal with it */
+	struct net_device *dev = priv->ndev;
+	u16 infofid;
+	struct {
+		u16 len;
+		u16 type;
+	} __attribute__ ((packed)) info;
+	int err;
+
+	/* This is an answer to an INQUIRE command that we did earlier,
+	 * or an information "event" generated by the card
+	 * The controller return to us a pseudo frame containing
+	 * the information in question - Jean II */
+	infofid = hermes_read_regn(hw, INFOFID);
+	DEBUG(3, "%s: __orinoco_ev_info(): INFOFID=0x%04x\n", dev->name,
+	      infofid);
+
+	/* Read the info frame header - don't try too hard */
+	err = hermes_bap_pread(hw, IRQ_BAP, &info, sizeof(info),
+			       infofid, 0);
+	if (err) {
+		printk(KERN_ERR "%s: error %d reading info frame. "
+		       "Frame dropped.\n", dev->name, err);
+		return;
+	}
+	
+	switch (le16_to_cpu(info.type)) {
+	case HERMES_INQ_TALLIES: {
+		struct hermes_tallies_frame tallies;
+		struct iw_statistics *wstats = &priv->wstats;
+		int len = le16_to_cpu(info.len) - 1;
+		
+		if (len > (sizeof(tallies) / 2)) {
+			DEBUG(1, "%s: tallies frame too long.\n", dev->name);
+			len = sizeof(tallies) / 2;
+		}
+		
+		/* Read directly the data (no seek) */
+		hermes_read_words(hw, HERMES_DATA1, (void *) &tallies, len);
+		
+		/* Increment our various counters */
+		/* wstats->discard.nwid - no wrong BSSID stuff */
+		wstats->discard.code +=
+			le16_to_cpu(tallies.RxWEPUndecryptable);
+		if (len == (sizeof(tallies) / 2))  
+			wstats->discard.code +=
+				le16_to_cpu(tallies.RxDiscards_WEPICVError) +
+				le16_to_cpu(tallies.RxDiscards_WEPExcluded);
+		wstats->discard.misc +=
+			le16_to_cpu(tallies.TxDiscardsWrongSA);
+#if WIRELESS_EXT > 11
+		wstats->discard.fragment +=
+			le16_to_cpu(tallies.RxMsgInBadMsgFragments);
+		wstats->discard.retries +=
+			le16_to_cpu(tallies.TxRetryLimitExceeded);
+		/* wstats->miss.beacon - no match */
+#if ORINOCO_DEBUG > 3
+		/* Hack for debugging - should not be taken as an example */
+		wstats->discard.nwid += le16_to_cpu(tallies.TxUnicastFrames);
+		wstats->miss.beacon += le16_to_cpu(tallies.RxUnicastFrames);
+#endif
+#endif /* WIRELESS_EXT > 11 */
+	}
+	break;
+	default:
+		DEBUG(1, "%s: Unknown information frame received (type %04x).\n",
+		      priv->ndev->name, le16_to_cpu(info.type));
+		/* We don't actually do anything about it */
+		break;
+	}
 }
 
-static void __dldwd_ev_rx(dldwd_priv_t *priv, hermes_t *hw)
+static void __orinoco_ev_rx(struct orinoco_private *priv, hermes_t *hw)
 {
-	struct net_device *dev = &priv->ndev;
+	struct net_device *dev = priv->ndev;
 	struct net_device_stats *stats = &priv->stats;
 	struct iw_statistics *wstats = &priv->wstats;
 	struct sk_buff *skb = NULL;
-	int l = RX_EIO_RETRY;
 	u16 rxfid, status;
 	int length, data_len, data_off;
 	char *p;
-	struct dldwd_frame_hdr hdr;
+	struct hermes_rx_descriptor desc;
+	struct header_struct hdr;
 	struct ethhdr *eh;
 	int err;
 
 	rxfid = hermes_read_regn(hw, RXFID);
-	DEBUG(3, "__dldwd_ev_rx(): RXFID=0x%04x\n", rxfid);
+	DEBUG(3, "__orinoco_ev_rx(): RXFID=0x%04x\n", rxfid);
 
-	/* We read in the entire frame header here. This isn't really
-	   necessary, since we ignore most of it, but it's
-	   conceptually simpler. We can tune this later if
-	   necessary. */
-	do {
-		err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr),
-				       rxfid, 0);
-	} while ( (err == -EIO) && (--l) );
+	err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc),
+			       rxfid, 0);
 	if (err) {
-		if (err == -EIO)
-			DEBUG(1, "%s: EIO reading frame header.\n", dev->name);
-		else
-			printk(KERN_ERR "%s: error %d reading frame header. "
-			       "Frame dropped.\n", dev->name, err);
+		printk(KERN_ERR "%s: error %d reading Rx descriptor. "
+		       "Frame dropped.\n", dev->name, err);
 		stats->rx_errors++;
 		goto drop;
 	}
-	DEBUG(2, "%s: BAP read suceeded: l=%d\n", dev->name, l);
 
-	status = le16_to_cpu(hdr.desc.status);
+	status = le16_to_cpu(desc.status);
 	
 	if (status & HERMES_RXSTAT_ERR) {
-		if ((status & HERMES_RXSTAT_ERR) == HERMES_RXSTAT_BADCRC) {
-			stats->rx_crc_errors++;
-			DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", dev->name);
-			show_rx_frame(&hdr);
-		} else if ((status & HERMES_RXSTAT_ERR)
-			   == HERMES_RXSTAT_UNDECRYPTABLE) {
+		if (status & HERMES_RXSTAT_UNDECRYPTABLE) {
 			wstats->discard.code++;
-			printk(KERN_WARNING "%s: Undecryptable frame on Rx. Frame dropped.\n",
+			DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n",
 			       dev->name);
 		} else {
-			wstats->discard.misc++;
-			printk("%s: Unknown Rx error (0x%x). Frame dropped.\n",
-			       dev->name, status & HERMES_RXSTAT_ERR);
+			stats->rx_crc_errors++;
+			DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", dev->name);
 		}
 		stats->rx_errors++;
 		goto drop;
 	}
 
-	length = le16_to_cpu(hdr.p80211.data_len);
-	/* Yes, you heard right, that's le16. 802.2 and 802.3 are
-	   big-endian, but 802.11 is little-endian believe it or
-	   not. */
-	/* Correct. 802.3 is big-endian byte order and little endian bit
-	 * order, whereas 802.11 is little endian for both byte and bit
-	 * order. That's specified in the 802.11 spec. - Jean II */
+	/* For now we ignore the 802.11 header completely, assuming
+           that the card's firmware has handled anything vital */
+
+	err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr),
+			       rxfid, HERMES_802_3_OFFSET);
+	if (err) {
+		printk(KERN_ERR "%s: error %d reading frame header. "
+		       "Frame dropped.\n", dev->name, err);
+		stats->rx_errors++;
+		goto drop;
+	}
+
+	length = ntohs(hdr.len);
 	
-	/* Sanity check */
-	if (length > MAX_FRAME_SIZE) {
+	/* Sanity checks */
+	if (length < sizeof(struct header_struct)) {
+		printk(KERN_WARNING "%s: Undersized frame received (%d bytes)\n",
+		       dev->name, length);
+		stats->rx_length_errors++;
+		stats->rx_errors++;
+		goto drop;
+	}
+	if (length > IEEE802_11_DATA_LEN) {
 		printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n",
 		       dev->name, length);
 		stats->rx_length_errors++;
@@ -1203,45 +1381,38 @@
 	 */
 	if(((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) ||
 	   ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) ||
-	   (!memcmp(&hdr.p8022, &encaps_hdr, 3))) {
+	   is_snap(&hdr)) {
 		/* These indicate a SNAP within 802.2 LLC within
 		   802.11 frame which we'll need to de-encapsulate to
 		   the original EthernetII frame. */
 
 		/* Remove SNAP header, reconstruct EthernetII frame */
 		data_len = length - ENCAPS_OVERHEAD;
-		data_off = sizeof(hdr);
+		data_off = HERMES_802_3_OFFSET + sizeof(hdr);
 
 		eh = (struct ethhdr *)skb_put(skb, ETH_HLEN);
 
-		memcpy(eh, &hdr.p8023, sizeof(hdr.p8023));
+		memcpy(eh, &hdr, 2 * ETH_ALEN);
 		eh->h_proto = hdr.ethertype;
 	} else {
-		/* All other cases indicate a genuine 802.3 frame.
-		 * No decapsulation needed */
-
-		/* Otherwise, we just throw the whole thing in,
-		 * and hope the protocol layer can deal with it
-		 * as 802.3 */
+		/* All other cases indicate a genuine 802.3 frame.  No
+		   decapsulation needed.  We just throw the whole
+		   thing in, and hope the protocol layer can deal with
+		   it as 802.3 */
 		data_len = length;
-		data_off = P8023_OFFSET;
+		data_off = HERMES_802_3_OFFSET;
+		/* FIXME: we re-read from the card data we already read here */
 	}
 
 	p = skb_put(skb, data_len);
-	do {
-		err = hermes_bap_pread(hw, IRQ_BAP, p, RUP_EVEN(data_len),
-				       rxfid, data_off);
-	} while ( (err == -EIO) && (--l) );
+	err = hermes_bap_pread(hw, IRQ_BAP, p, RUP_EVEN(data_len),
+			       rxfid, data_off);
 	if (err) {
-		if (err == -EIO)
-			DEBUG(1, "%s: EIO reading frame header.\n", dev->name);
-		else
-			printk(KERN_ERR "%s: error %d reading frame header. "
-			       "Frame dropped.\n", dev->name, err);
+		printk(KERN_ERR "%s: error %d reading frame header. "
+		       "Frame dropped.\n", dev->name, err);
 		stats->rx_errors++;
 		goto drop;
 	}
-	DEBUG(2, "%s: BAP read suceeded: l=%d\n", dev->name, l);
 
 	dev->last_rx = jiffies;
 	skb->dev = dev;
@@ -1249,11 +1420,10 @@
 	skb->ip_summed = CHECKSUM_NONE;
 	
 	/* Process the wireless stats if needed */
-	dldwd_stat_gather(dev, skb, &hdr);
+	orinoco_stat_gather(dev, skb, &desc);
 
 	/* Pass the packet to the networking stack */
 	netif_rx(skb);
-	dev->last_rx = jiffies;
 	stats->rx_packets++;
 	stats->rx_bytes += length;
 
@@ -1265,55 +1435,92 @@
 	return;
 }
 
-static void __dldwd_ev_txexc(dldwd_priv_t *priv, hermes_t *hw)
+static void __orinoco_ev_txexc(struct orinoco_private *priv, hermes_t *hw)
 {
-	struct net_device *dev = &priv->ndev;
+	struct net_device *dev = priv->ndev;
 	struct net_device_stats *stats = &priv->stats;
+	u16 fid = hermes_read_regn(hw, TXCOMPLFID);
+	struct hermes_tx_descriptor desc;
+	int err = 0;
 
-	printk(KERN_WARNING "%s: Tx error!\n", dev->name);
+	if (fid == DUMMY_FID)
+		return; /* Nothing's really happened */
 
-	netif_wake_queue(dev);
+	err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc), fid, 0);
+	if (err) {
+		printk(KERN_WARNING "%s: Unable to read descriptor on Tx error "
+		       "(FID=%04X error %d)\n",
+		       dev->name, fid, err);
+	} else {
+		DEBUG(1, "%s: Tx error, status %d\n",
+		      dev->name, le16_to_cpu(desc.status));
+	}
+	
 	stats->tx_errors++;
+
+	hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
 }
 
-static void __dldwd_ev_tx(dldwd_priv_t *priv, hermes_t *hw)
+static void __orinoco_ev_tx(struct orinoco_private *priv, hermes_t *hw)
 {
-	struct net_device *dev = &priv->ndev;
+/*  	struct net_device *dev = priv->ndev; */
 	struct net_device_stats *stats = &priv->stats;
+/*  	u16 fid = hermes_read_regn(hw, TXCOMPLFID); */
 
-	DEBUG(3, "%s: Transmit completed\n", dev->name);
+/*  	DEBUG(2, "%s: Transmit completed (FID=%04X)\n", priv->ndev->name, fid); */
 
 	stats->tx_packets++;
-	netif_wake_queue(dev);
+
+	hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
 }
 
-static void __dldwd_ev_alloc(dldwd_priv_t *priv, hermes_t *hw)
+static void __orinoco_ev_alloc(struct orinoco_private *priv, hermes_t *hw)
 {
-	u16 allocfid;
+	struct net_device *dev = priv->ndev;
+	u16 fid = hermes_read_regn(hw, ALLOCFID);
 
-	allocfid = hermes_read_regn(hw, ALLOCFID);
-	DEBUG(3, "%s: Allocation complete FID=0x%04x\n", priv->ndev.name, allocfid);
+	DEBUG(3, "%s: Allocation complete FID=0x%04x\n", priv->ndev->name, fid);
 
-	/* For some reason we don't seem to get transmit completed events properly */
-	if (allocfid == priv->txfid)
-		__dldwd_ev_tx(priv, hw);
+	if (fid != priv->txfid) {
+		if (fid != DUMMY_FID)
+			printk(KERN_WARNING "%s: Allocate event on unexpected fid (%04X)\n",
+			       dev->name, fid);
+		return;
+	} else {
+		netif_wake_queue(dev);
+	}
+
+	hermes_write_regn(hw, ALLOCFID, DUMMY_FID);
+}
+
+struct sta_id {
+	u16 id, vendor, major, minor;
+} __attribute__ ((packed));
 
-/* 	hermes_write_regn(hw, ALLOCFID, 0); */
+static int determine_firmware_type(struct net_device *dev, struct sta_id *sta_id)
+{
+	u32 firmver = ((u32)sta_id->major << 16) | sta_id->minor;
+	
+	if (sta_id->vendor == 1)
+		return FIRMWARE_TYPE_AGERE;
+	else if ((sta_id->vendor == 2) &&
+		   ((firmver == 0x10001) || (firmver == 0x20001)))
+		return FIRMWARE_TYPE_SYMBOL;
+	else
+		return FIRMWARE_TYPE_INTERSIL;
 }
 
 static void determine_firmware(struct net_device *dev)
 {
-	dldwd_priv_t *priv = dev->priv;
+	struct orinoco_private *priv = dev->priv;
 	hermes_t *hw = &priv->hw;
 	int err;
-	struct sta_id {
-		u16 id, vendor, major, minor;
-	} __attribute__ ((packed)) sta_id;
+	struct sta_id sta_id;
 	u32 firmver;
+	char tmp[SYMBOL_MAX_VER_LEN+1];
 
 	/* Get the firmware version */
-	err = HERMES_READ_RECORD(hw, USER_BAP,
-				 HERMES_RID_STAIDENTITY, &sta_id);
+	err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id);
 	if (err) {
 		printk(KERN_WARNING "%s: Error %d reading firmware info. Wildly guessing capabilities...\n",
 		       dev->name, err);
@@ -1330,21 +1537,29 @@
 	       dev->name, sta_id.id, sta_id.vendor,
 	       sta_id.major, sta_id.minor);
 
-	/* Determine capabilities from the firmware version */
+	if (! priv->firmware_type)
+		priv->firmware_type = determine_firmware_type(dev, &sta_id);
+
+	/* Default capabilities */
+	priv->has_sensitivity = 1;
+	priv->has_mwo = 0;
+	priv->has_preamble = 0;
+	priv->has_port3 = 1;
+	priv->has_ibss = 1;
+	priv->has_ibss_any = 0;
+	priv->has_wep = 0;
+	priv->has_big_wep = 0;
+	priv->broken_cor_reset = 0;
 
-	if (sta_id.vendor == 1) {
+	/* Determine capabilities from the firmware version */
+	switch (priv->firmware_type) {
+	case FIRMWARE_TYPE_AGERE:
 		/* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout,
 		   ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */
 		printk(KERN_DEBUG "%s: Looks like a Lucent/Agere firmware "
 		       "version %d.%02d\n", dev->name,
 		       sta_id.major, sta_id.minor);
 
-		priv->firmware_type = FIRMWARE_TYPE_LUCENT;
-		priv->tx_rate_ctrl = 0x3;	/* 11 Mb/s auto */
-		priv->need_card_reset = 0;
-		priv->broken_reset = 0;
-		priv->broken_allocate = 0;
-		priv->has_port3 = 1;		/* Still works in 7.28 */
 		priv->has_ibss = (firmver >= 0x60006);
 		priv->has_ibss_any = (firmver >= 0x60010);
 		priv->has_wep = (firmver >= 0x40020);
@@ -1352,21 +1567,22 @@
 					  Gold cards from the others? */
 		priv->has_mwo = (firmver >= 0x60000);
 		priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
-		priv->has_preamble = 0;
 		priv->ibss_port = 1;
-		/* Tested with Lucent firmware :
+
+		/* FIXME: Which firmware really do have a broken reset */
+		priv->broken_cor_reset = (firmver < 0x60000);
+		/* Tested with Agere firmware :
 		 *	1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
 		 * Tested CableTron firmware : 4.32 => Anton */
-	} else if ((sta_id.vendor == 2) &&
-		   ((firmver == 0x10001) || (firmver == 0x20001))) {
+		break;
+	case FIRMWARE_TYPE_SYMBOL:
 		/* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */
 		/* Intel MAC : 00:02:B3:* */
 		/* 3Com MAC : 00:50:DA:* */
-		char tmp[SYMBOL_MAX_VER_LEN+1];
-
 		memset(tmp, 0, sizeof(tmp));
 		/* Get the Symbol firmware version */
-		err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SYMBOL_SECONDARY_VER,
+		err = hermes_read_ltv(hw, USER_BAP,
+				      HERMES_RID_SECONDARYVERSION_SYMBOL,
 				      SYMBOL_MAX_VER_LEN, NULL, &tmp);
 		if (err) {
 			printk(KERN_WARNING
@@ -1390,22 +1606,16 @@
 		       "version [%s] (parsing to %X)\n", dev->name,
 		       tmp, firmver);
 
-		priv->firmware_type = FIRMWARE_TYPE_SYMBOL;
-		priv->tx_rate_ctrl = 0xF;	/* 11 Mb/s auto */
-		priv->need_card_reset = 1;
-		priv->broken_reset = 0;
-		priv->broken_allocate = 1;
-		priv->has_port3 = 1;
 		priv->has_ibss = (firmver >= 0x20000);
 		priv->has_wep = (firmver >= 0x15012);
 		priv->has_big_wep = (firmver >= 0x20000);
-		priv->has_mwo = 0;
 		priv->has_pm = (firmver >= 0x20000) && (firmver < 0x22000);
 		priv->has_preamble = (firmver >= 0x20000);
 		priv->ibss_port = 4;
 		/* Tested with Intel firmware : 0x20015 => Jean II */
 		/* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
-	} else {
+		break;
+	case FIRMWARE_TYPE_INTERSIL:
 		/* D-Link, Linksys, Adtron, ZoomAir, and many others...
 		 * Samsung, Compaq 100/200 and Proxim are slightly
 		 * different and less well tested */
@@ -1415,27 +1625,21 @@
 		       "version %d.%02d\n", dev->name,
 		       sta_id.major, sta_id.minor);
 
-		priv->firmware_type = FIRMWARE_TYPE_INTERSIL;
-		priv->tx_rate_ctrl = 0xF;	/* 11 Mb/s auto */
-		priv->need_card_reset = 0;
-		priv->broken_reset = 0;
-		priv->broken_allocate = 0;
-		priv->has_port3 = 1;
 		priv->has_ibss = (firmver >= 0x00007); /* FIXME */
-		priv->has_wep = (firmver >= 0x00008);
-		priv->has_big_wep = priv->has_wep;
-		priv->has_mwo = 0;
+		priv->has_big_wep = priv->has_wep = (firmver >= 0x00008);
 		priv->has_pm = (firmver >= 0x00007);
-		priv->has_preamble = 0;
 
 		if (firmver >= 0x00008)
 			priv->ibss_port = 0;
 		else {
 			printk(KERN_NOTICE "%s: Intersil firmware earlier "
-			       "than v0.08 - several features not supported.",
+			       "than v0.08 - several features not supported\n",
 			       dev->name);
 			priv->ibss_port = 1;
 		}
+		break;
+	default:
+		break;
 	}
 }
 
@@ -1443,19 +1647,21 @@
  * struct net_device methods
  */
 
-int
-dldwd_init(struct net_device *dev)
+static int
+orinoco_init(struct net_device *dev)
 {
-	dldwd_priv_t *priv = dev->priv;
+	struct orinoco_private *priv = dev->priv;
 	hermes_t *hw = &priv->hw;
 	int err = 0;
-	hermes_id_t nickbuf;
+	struct hermes_idstring nickbuf;
 	u16 reclen;
 	int len;
 
-	TRACE_ENTER("dldwd");
+	TRACE_ENTER("orinoco");
+
+	orinoco_lock(priv);
 
-	dldwd_lock(priv);
+	priv->nicbuf_size = IEEE802_11_FRAME_LEN + ETH_HLEN;
 
 	/* Do standard firmware reset */
 	err = hermes_reset(hw);
@@ -1468,20 +1674,20 @@
 	determine_firmware(dev);
 
 	if (priv->has_port3)
-		printk(KERN_DEBUG "%s: Ad-hoc demo mode supported.\n", dev->name);
+		printk(KERN_DEBUG "%s: Ad-hoc demo mode supported\n", dev->name);
 	if (priv->has_ibss)
-		printk(KERN_DEBUG "%s: IEEE standard IBSS ad-hoc mode supported.\n",
+		printk(KERN_DEBUG "%s: IEEE standard IBSS ad-hoc mode supported\n",
 		       dev->name);
 	if (priv->has_wep) {
 		printk(KERN_DEBUG "%s: WEP supported, ", dev->name);
 		if (priv->has_big_wep)
-			printk("\"128\"-bit key.\n");
+			printk("104-bit key\n");
 		else
-			printk("40-bit key.\n");
+			printk("40-bit key\n");
 	}
 
 	/* Get the MAC address */
-	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNF_MACADDR,
+	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
 			      ETH_ALEN, NULL, dev->dev_addr);
 	if (err) {
 		printk(KERN_WARNING "%s: failed to read MAC address!\n",
@@ -1495,15 +1701,15 @@
 	       dev->dev_addr[5]);
 
 	/* Get the station name */
-	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNF_NICKNAME,
+	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
 			      sizeof(nickbuf), &reclen, &nickbuf);
 	if (err) {
-		printk(KERN_ERR "%s: failed to read station name!n",
+		printk(KERN_ERR "%s: failed to read station name\n",
 		       dev->name);
 		goto out;
 	}
 	if (nickbuf.len)
-		len = min_t(u16, IW_ESSID_MAX_SIZE, le16_to_cpu(nickbuf.len));
+		len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len));
 	else
 		len = min(IW_ESSID_MAX_SIZE, 2 * reclen);
 	memcpy(priv->nick, &nickbuf.val, len);
@@ -1512,7 +1718,8 @@
 	printk(KERN_DEBUG "%s: Station name \"%s\"\n", dev->name, priv->nick);
 
 	/* Get allowed channels */
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNEL_LIST, &priv->channel_mask);
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST,
+				  &priv->channel_mask);
 	if (err) {
 		printk(KERN_ERR "%s: failed to read channel list!\n",
 		       dev->name);
@@ -1520,14 +1727,15 @@
 	}
 
 	/* Get initial AP density */
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, &priv->ap_density);
-	if (err) {
-		printk(KERN_ERR "%s: failed to read AP density!\n", dev->name);
-		goto out;
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE,
+				  &priv->ap_density);
+	if (err || priv->ap_density < 1 || priv->ap_density > 3) {
+		priv->has_sensitivity = 0;
 	}
 
 	/* Get initial RTS threshold */
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_RTS_THRESH, &priv->rts_thresh);
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
+				  &priv->rts_thresh);
 	if (err) {
 		printk(KERN_ERR "%s: failed to read RTS threshold!\n", dev->name);
 		goto out;
@@ -1535,10 +1743,11 @@
 
 	/* Get initial fragmentation settings */
 	if (priv->has_mwo)
-		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_MWO_ROBUST,
+		err = hermes_read_wordrec(hw, USER_BAP,
+					  HERMES_RID_CNFMWOROBUST_AGERE,
 					  &priv->mwo_robust);
 	else
-		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_FRAG_THRESH,
+		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
 					  &priv->frag_thresh);
 	if (err) {
 		printk(KERN_ERR "%s: failed to read fragmentation settings!\n", dev->name);
@@ -1549,14 +1758,16 @@
 	if (priv->has_pm) {
 		priv->pm_on = 0;
 		priv->pm_mcast = 1;
-		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD,
+		err = hermes_read_wordrec(hw, USER_BAP,
+					  HERMES_RID_CNFMAXSLEEPDURATION,
 					  &priv->pm_period);
 		if (err) {
 			printk(KERN_ERR "%s: failed to read power management period!\n",
 			       dev->name);
 			goto out;
 		}
-		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER,
+		err = hermes_read_wordrec(hw, USER_BAP,
+					  HERMES_RID_CNFPMHOLDOVERDURATION,
 					  &priv->pm_timeout);
 		if (err) {
 			printk(KERN_ERR "%s: failed to read power management timeout!\n",
@@ -1567,7 +1778,8 @@
 
 	/* Preamble setup */
 	if (priv->has_preamble) {
-		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_PREAMBLE, &priv->preamble);
+		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFPREAMBLE_SYMBOL,
+					  &priv->preamble);
 		if (err)
 			goto out;
 	}
@@ -1577,57 +1789,57 @@
 	/* By default use IEEE/IBSS ad-hoc mode if we have it */
 	priv->prefer_port3 = priv->has_port3 && (! priv->has_ibss);
 	set_port_type(priv);
+	priv->channel = 10; /* default channel, more-or-less arbitrary */
 
 	priv->promiscuous = 0;
-	priv->allmulti = 0;
 	priv->wep_on = 0;
 	priv->tx_key = 0;
 
 	printk(KERN_DEBUG "%s: ready\n", dev->name);
 
  out:
-	dldwd_unlock(priv);
+	orinoco_unlock(priv);
 
-	TRACE_EXIT("dldwd");
+	TRACE_EXIT("orinoco");
 
 	return err;
 }
 
 struct net_device_stats *
-dldwd_get_stats(struct net_device *dev)
+orinoco_get_stats(struct net_device *dev)
 {
-	dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
+	struct orinoco_private *priv = (struct orinoco_private *)dev->priv;
 	
 	return &priv->stats;
 }
 
 struct iw_statistics *
-dldwd_get_wireless_stats(struct net_device *dev)
+orinoco_get_wireless_stats(struct net_device *dev)
 {
-	dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
+	struct orinoco_private *priv = (struct orinoco_private *)dev->priv;
 	hermes_t *hw = &priv->hw;
 	struct iw_statistics *wstats = &priv->wstats;
 	int err = 0;
 
-	if (!priv->hw_ready)
-		return NULL;
+	if (! netif_device_present(dev))
+		return NULL; /* FIXME: We may be able to do better than this */
 
-	dldwd_lock(priv);
+	orinoco_lock(priv);
 
 	if (priv->iw_mode == IW_MODE_ADHOC) {
 		memset(&wstats->qual, 0, sizeof(wstats->qual));
-#ifdef WIRELESS_SPY
 		/* If a spy address is defined, we report stats of the
 		 * first spy address - Jean II */
-		if (priv->spy_number > 0) {
+		if (SPY_NUMBER(priv)) {
 			wstats->qual.qual = priv->spy_stat[0].qual;
 			wstats->qual.level = priv->spy_stat[0].level;
 			wstats->qual.noise = priv->spy_stat[0].noise;
 			wstats->qual.updated = priv->spy_stat[0].updated;
 		}
-#endif /* WIRELESS_SPY */
 	} else {
-		dldwd_commsqual_t cq;
+		struct {
+			u16 qual, signal, noise;
+		} __attribute__ ((packed)) cq;
 
 		err = HERMES_READ_RECORD(hw, USER_BAP,
 					 HERMES_RID_COMMSQUALITY, &cq);
@@ -1641,7 +1853,14 @@
 		wstats->qual.updated = 7;
 	}
 
-	dldwd_unlock(priv);
+	/* We can't really wait for the tallies inquiry command to
+	 * complete, so we just use the previous results and trigger
+	 * a new tallies inquiry command for next time - Jean II */
+	/* FIXME: Hmm.. seems a bit ugly, I wonder if there's a way to
+	   do better - dgibson */
+	err = hermes_inquire(hw, HERMES_INQ_TALLIES);
+               
+	orinoco_unlock(priv);
 
 	if (err)
 		return NULL;
@@ -1649,11 +1868,10 @@
 	return wstats;
 }
 
-#ifdef WIRELESS_SPY
-static inline void dldwd_spy_gather(struct net_device *dev, u_char *mac,
+static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac,
 				    int level, int noise)
 {
-	dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
+	struct orinoco_private *priv = (struct orinoco_private *)dev->priv;
 	int i;
 
 	/* Gather wireless spy statistics: for each packet, compare the
@@ -1662,18 +1880,17 @@
 		if (!memcmp(mac, priv->spy_address[i], ETH_ALEN)) {
 			priv->spy_stat[i].level = level - 0x95;
 			priv->spy_stat[i].noise = noise - 0x95;
-			priv->spy_stat[i].qual = level - noise;
+			priv->spy_stat[i].qual = (level > noise) ? (level - noise) : 0;
 			priv->spy_stat[i].updated = 7;
 		}
 }
-#endif /* WIRELESS_SPY */
 
 void
-dldwd_stat_gather( struct net_device *dev,
-		   struct sk_buff *skb,
-		   struct dldwd_frame_hdr *hdr)
+orinoco_stat_gather(struct net_device *dev,
+		    struct sk_buff *skb,
+		    struct hermes_rx_descriptor *desc)
 {
-	dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
+	struct orinoco_private *priv = (struct orinoco_private *)dev->priv;
 
 	/* Using spy support with lots of Rx packets, like in an
 	 * infrastructure (AP), will really slow down everything, because
@@ -1683,24 +1900,18 @@
 	 * Note that to get here, you need both WIRELESS_SPY
 	 * compiled in AND some addresses in the list !!!
 	 */
-#ifdef WIRELESS_SPY
 	/* Note : gcc will optimise the whole section away if
 	 * WIRELESS_SPY is not defined... - Jean II */
-	if (priv->spy_number > 0) {
-		u8 *stats = (u8 *) &(hdr->desc.q_info);
-		/* This code may look strange. Everywhere we are using 16 bit
-		 * ints except here. I've verified that these are are the
-		 * correct values. Please check on PPC - Jean II */
-
-		dldwd_spy_gather(dev, skb->mac.raw + ETH_ALEN, (int)stats[1], (int)stats[0]);
+	if (SPY_NUMBER(priv)) {
+		orinoco_spy_gather(dev, skb->mac.raw + ETH_ALEN,
+				   desc->signal, desc->silence);
 	}
-#endif /* WIRELESS_SPY */
 }
 
-int
-dldwd_xmit(struct sk_buff *skb, struct net_device *dev)
+static int
+orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
+	struct orinoco_private *priv = (struct orinoco_private *)dev->priv;
 	struct net_device_stats *stats = &priv->stats;
 	hermes_t *hw = &priv->hw;
 	int err = 0;
@@ -1708,8 +1919,7 @@
 	char *p;
 	struct ethhdr *eh;
 	int len, data_len, data_off;
-	struct dldwd_frame_hdr hdr;
-	hermes_response_t resp;
+	struct hermes_tx_descriptor desc;
 
 	if (! netif_running(dev)) {
 		printk(KERN_ERR "%s: Tx on stopped device!\n",
@@ -1724,90 +1934,69 @@
 		return 1;
 	}
 	
-	dldwd_lock(priv);
+	orinoco_lock(priv);
 
 	/* Length of the packet body */
+	/* FIXME: what if the skb is smaller than this? */
 	len = max_t(int,skb->len - ETH_HLEN, ETH_ZLEN);
 
 	eh = (struct ethhdr *)skb->data;
 
-	/* Build the IEEE 802.11 header */
-	memset(&hdr, 0, sizeof(hdr));
-	memcpy(hdr.p80211.addr1, eh->h_dest, ETH_ALEN);
-	memcpy(hdr.p80211.addr2, eh->h_source, ETH_ALEN);
-	hdr.p80211.frame_ctl = DLDWD_FTYPE_DATA;
+	memset(&desc, 0, sizeof(desc));
+ 	desc.tx_control = cpu_to_le16(HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX);
+	err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), txfid, 0);
+	if (err) {
+		printk(KERN_ERR "%s: Error %d writing Tx descriptor to BAP\n",
+		       dev->name, err);
+		stats->tx_errors++;
+		goto fail;
+	}
 
 	/* Encapsulate Ethernet-II frames */
 	if (ntohs(eh->h_proto) > 1500) { /* Ethernet-II frame */
+		struct header_struct hdr;
 		data_len = len;
-		data_off = sizeof(hdr);
+		data_off = HERMES_802_3_OFFSET + sizeof(hdr);
 		p = skb->data + ETH_HLEN;
 
-		/* 802.11 header */
-		hdr.p80211.data_len = cpu_to_le16(data_len + ENCAPS_OVERHEAD);
-
 		/* 802.3 header */
-		memcpy(hdr.p8023.h_dest, eh->h_dest, ETH_ALEN);
-		memcpy(hdr.p8023.h_source, eh->h_source, ETH_ALEN);
-		hdr.p8023.h_proto = htons(data_len + ENCAPS_OVERHEAD);
+		memcpy(hdr.dest, eh->h_dest, ETH_ALEN);
+		memcpy(hdr.src, eh->h_source, ETH_ALEN);
+		hdr.len = htons(data_len + ENCAPS_OVERHEAD);
 		
 		/* 802.2 header */
-		if (! use_old_encaps) 
-			memcpy(&hdr.p8022, &encaps_hdr,
-			       sizeof(encaps_hdr));
-		else
-			memcpy(&hdr.p8022, &encaps_hdr,
-			       sizeof(old_encaps_hdr));
+		memcpy(&hdr.dsap, &encaps_hdr, sizeof(encaps_hdr));
 			
 		hdr.ethertype = eh->h_proto;
 		err  = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr),
-					 txfid, 0);
+					 txfid, HERMES_802_3_OFFSET);
 		if (err) {
-			if (err == -EIO)
-				/* We get these errors reported by the
-				   firmware every so often apparently at
-				   random.  Let the upper layers
-				   handle the retry */
-				DEBUG(1, "%s: DEBUG: EIO writing packet header to BAP\n", dev->name);
-			else
-				printk(KERN_ERR "%s: Error %d writing packet header to BAP\n",
-				       dev->name, err);
+			printk(KERN_ERR "%s: Error %d writing packet header to BAP\n",
+			       dev->name, err);
 			stats->tx_errors++;
 			goto fail;
 		}
 	} else { /* IEEE 802.3 frame */
 		data_len = len + ETH_HLEN;
-		data_off = P8023_OFFSET;
+		data_off = HERMES_802_3_OFFSET;
 		p = skb->data;
-		
-		/* 802.11 header */
-		hdr.p80211.data_len = cpu_to_le16(len);
-		err = hermes_bap_pwrite(hw, USER_BAP, &hdr, P8023_OFFSET,
-					txfid, 0);
-		if (err) {
-			printk(KERN_ERR
-			       "%s: Error %d writing packet header to BAP\n",
-			       dev->name, err);
-			stats->tx_errors++;
-			goto fail;
-		}
 	}
 
 	/* Round up for odd length packets */
 	err = hermes_bap_pwrite(hw, USER_BAP, p, RUP_EVEN(data_len), txfid, data_off);
 	if (err) {
-		if (err == -EIO)
-			DEBUG(1, "%s: DEBUG: EIO writing packet header to BAP\n", dev->name);
-		else
-			printk(KERN_ERR "%s: Error %d writing packet header to BAP",
-			       dev->name, err);
+		printk(KERN_ERR "%s: Error %d writing packet to BAP\n",
+		       dev->name, err);
 		stats->tx_errors++;
 		goto fail;
 	}
 
 	/* Finally, we actually initiate the send */
-	err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL, txfid, &resp);
+	netif_stop_queue(dev);
+
+	err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL, txfid, NULL);
 	if (err) {
+		netif_start_queue(dev);
 		printk(KERN_ERR "%s: Error %d transmitting packet\n", dev->name, err);
 		stats->tx_errors++;
 		goto fail;
@@ -1816,31 +2005,30 @@
 	dev->trans_start = jiffies;
 	stats->tx_bytes += data_off + data_len;
 
-	netif_stop_queue(dev);
-
-	dldwd_unlock(priv);
+	orinoco_unlock(priv);
 
 	dev_kfree_skb(skb);
 
 	return 0;
  fail:
 
-	dldwd_unlock(priv);
+	orinoco_unlock(priv);
 	return err;
 }
 
-void
-dldwd_tx_timeout(struct net_device *dev)
+static void
+orinoco_tx_timeout(struct net_device *dev)
 {
-	dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
+	struct orinoco_private *priv = (struct orinoco_private *)dev->priv;
 	struct net_device_stats *stats = &priv->stats;
+	struct hermes *hw = &priv->hw;
 	int err = 0;
 
-	printk(KERN_WARNING "%s: Tx timeout! Resetting card.\n", dev->name);
+	printk(KERN_WARNING "%s: Tx timeout! Resetting card. ALLOCFID=%04x, TXCOMPLFID=%04x, EVSTAT=%04x\n", dev->name, hermes_read_regn(hw, ALLOCFID), hermes_read_regn(hw, TXCOMPLFID), hermes_read_regn(hw, EVSTAT));
 
 	stats->tx_errors++;
 
-	err = dldwd_reset(priv);
+	err = orinoco_reset(priv);
 	if (err)
 		printk(KERN_ERR "%s: Error %d resetting card on Tx timeout!\n",
 		       dev->name, err);
@@ -1850,9 +2038,113 @@
 	}
 }
 
-static int dldwd_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq)
+static int
+orinoco_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct orinoco_private *priv = dev->priv;
+	TRACE_ENTER(dev->name);
+
+	if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) )
+		return -EINVAL;
+
+	if ( (new_mtu + ENCAPS_OVERHEAD + IEEE802_11_HLEN) >
+	     (priv->nicbuf_size - ETH_HLEN) )
+		return -EINVAL;
+
+	dev->mtu = new_mtu;
+
+	TRACE_EXIT(dev->name);
+
+	return 0;
+}
+
+static void
+__orinoco_set_multicast_list(struct net_device *dev)
 {
-	dldwd_priv_t *priv = dev->priv;
+	struct orinoco_private *priv = dev->priv;
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	int promisc, mc_count;
+
+	/* We'll wait until it's ready. Anyway, the network doesn't call us
+	 * here until we are open - Jean II */
+	/* FIXME: do we need this test at all? */
+	if (! netif_device_present(dev)) {
+		printk(KERN_WARNING "%s: __orinoco_set_multicast_list() called while device "
+		       "not present.\n", dev->name);
+		return;
+	}
+
+	TRACE_ENTER(dev->name);
+
+	/* The Hermes doesn't seem to have an allmulti mode, so we go
+	 * into promiscuous mode and let the upper levels deal. */
+	if ( (dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) ||
+	     (dev->mc_count > MAX_MULTICAST(priv)) ) {
+		promisc = 1;
+		mc_count = 0;
+	} else {
+		promisc = 0;
+		mc_count = dev->mc_count;
+	}
+
+	if (promisc != priv->promiscuous) {
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNFPROMISCUOUSMODE,
+					   promisc);
+		if (err) {
+			printk(KERN_ERR "%s: Error %d setting PROMISCUOUSMODE to 1.\n",
+			       dev->name, err);
+		} else 
+			priv->promiscuous = promisc;
+	}
+
+	if (! promisc && (mc_count || priv->mc_count) ) {
+		struct dev_mc_list *p = dev->mc_list;
+		hermes_multicast_t mclist;
+		int i;
+
+		for (i = 0; i < mc_count; i++) {
+			/* Paranoia: */
+			if (! p)
+				BUG(); /* Multicast list shorter than mc_count */
+			if (p->dmi_addrlen != ETH_ALEN)
+				BUG(); /* Bad address size in multicast list */
+			
+			memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN);
+			p = p->next;
+		}
+		
+		if (p)
+			printk(KERN_WARNING "Multicast list is longer than mc_count\n");
+
+		err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFGROUPADDRESSES,
+				       HERMES_BYTES_TO_RECLEN(priv->mc_count * ETH_ALEN),
+				       &mclist);
+		if (err)
+			printk(KERN_ERR "%s: Error %d setting multicast list.\n",
+			       dev->name, err);
+		else
+			priv->mc_count = mc_count;
+	}
+
+	/* Since we can set the promiscuous flag when it wasn't asked
+	   for, make sure the net_device knows about it. */
+	if (priv->promiscuous)
+		dev->flags |= IFF_PROMISC;
+	else
+		dev->flags &= ~IFF_PROMISC;
+
+	TRACE_EXIT(dev->name);
+}
+
+/********************************************************************/
+/* Wireless extensions support                                      */
+/********************************************************************/
+
+static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq)
+{
+	struct orinoco_private *priv = dev->priv;
 	int err = 0;
 	int mode;
 	struct iw_range range;
@@ -1867,9 +2159,9 @@
 
 	rrq->length = sizeof(range);
 
-	dldwd_lock(priv);
+	orinoco_lock(priv);
 	mode = priv->iw_mode;
-	dldwd_unlock(priv);
+	orinoco_unlock(priv);
 
 	memset(&range, 0, sizeof(range));
 
@@ -1905,13 +2197,25 @@
 		range.max_qual.qual = 0;
 		range.max_qual.level = 0;
 		range.max_qual.noise = 0;
+#if WIRELESS_EXT > 11
+		range.avg_qual.qual = 0;
+		range.avg_qual.level = 0;
+		range.avg_qual.noise = 0;
+#endif /* WIRELESS_EXT > 11 */
+
 	} else {
 		range.max_qual.qual = 0x8b - 0x2f;
 		range.max_qual.level = 0x2f - 0x95 - 1;
 		range.max_qual.noise = 0x2f - 0x95 - 1;
+#if WIRELESS_EXT > 11
+		/* Need to get better values */
+		range.avg_qual.qual = 0x24;
+		range.avg_qual.level = 0xC2;
+		range.avg_qual.noise = 0x9E;
+#endif /* WIRELESS_EXT > 11 */
 	}
 
-	err = dldwd_hw_get_bitratelist(priv, &numrates,
+	err = orinoco_hw_get_bitratelist(priv, &numrates,
 				       range.bitrate, IW_MAX_BITRATES);
 	if (err)
 		return err;
@@ -1930,9 +2234,9 @@
 	range.min_frag = 256;
 	range.max_frag = 2346;
 
-	dldwd_lock(priv);
+	orinoco_lock(priv);
 	if (priv->has_wep) {
-		range.max_encoding_tokens = MAX_KEYS;
+		range.max_encoding_tokens = ORINOCO_MAX_KEYS;
 
 		range.encoding_size[0] = SMALL_KEY_SIZE;
 		range.num_encoding_sizes = 1;
@@ -1945,7 +2249,7 @@
 		range.num_encoding_sizes = 0;
 		range.max_encoding_tokens = 0;
 	}
-	dldwd_unlock(priv);
+	orinoco_unlock(priv);
 		
 	range.min_pmp = 0;
 	range.max_pmp = 65535000;
@@ -1977,30 +2281,30 @@
 	return 0;
 }
 
-static int dldwd_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq)
 {
-	dldwd_priv_t *priv = dev->priv;
+	struct orinoco_private *priv = dev->priv;
 	int index = (erq->flags & IW_ENCODE_INDEX) - 1;
 	int setindex = priv->tx_key;
 	int enable = priv->wep_on;
 	int restricted = priv->wep_restrict;
 	u16 xlen = 0;
 	int err = 0;
-	char keybuf[MAX_KEY_SIZE];
+	char keybuf[ORINOCO_MAX_KEY_SIZE];
 	
 	if (erq->pointer) {
 		/* We actually have a key to set */
-		if ( (erq->length < SMALL_KEY_SIZE) || (erq->length > MAX_KEY_SIZE) )
+		if ( (erq->length < SMALL_KEY_SIZE) || (erq->length > ORINOCO_MAX_KEY_SIZE) )
 			return -EINVAL;
 		
 		if (copy_from_user(keybuf, erq->pointer, erq->length))
 			return -EFAULT;
 	}
 	
-	dldwd_lock(priv);
+	orinoco_lock(priv);
 	
 	if (erq->pointer) {
-		if (erq->length > MAX_KEY_SIZE) {
+		if (erq->length > ORINOCO_MAX_KEY_SIZE) {
 			err = -E2BIG;
 			goto out;
 		}
@@ -2011,7 +2315,7 @@
 			goto out;
 		}
 		
-		if ((index < 0) || (index >= MAX_KEYS))
+		if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
 			index = priv->tx_key;
 		
 		if (erq->length > SMALL_KEY_SIZE) {
@@ -2030,7 +2334,7 @@
 		/* Important note : if the user do "iwconfig eth0 enc off",
 		 * we will arrive there with an index of -1. This is valid
 		 * but need to be taken care off... Jean II */
-		if ((index < 0) || (index >= MAX_KEYS)) {
+		if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) {
 			if((index != -1) || (erq->flags == 0)) {
 				err = -EINVAL;
 				goto out;
@@ -2063,22 +2367,22 @@
 	priv->wep_restrict = restricted;
 	
  out:
-	dldwd_unlock(priv);
+	orinoco_unlock(priv);
 
-	return 0;
+	return err;
 }
 
-static int dldwd_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq)
 {
-	dldwd_priv_t *priv = dev->priv;
+	struct orinoco_private *priv = dev->priv;
 	int index = (erq->flags & IW_ENCODE_INDEX) - 1;
 	u16 xlen = 0;
-	char keybuf[MAX_KEY_SIZE];
+	char keybuf[ORINOCO_MAX_KEY_SIZE];
 
 	
-	dldwd_lock(priv);
+	orinoco_lock(priv);
 
-	if ((index < 0) || (index >= MAX_KEYS))
+	if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
 		index = priv->tx_key;
 
 	erq->flags = 0;
@@ -2087,7 +2391,7 @@
 	erq->flags |= index + 1;
 	
 	/* Only for symbol cards - Jean II */
-	if (priv->firmware_type != FIRMWARE_TYPE_LUCENT) {
+	if (priv->firmware_type != FIRMWARE_TYPE_AGERE) {
 		if(priv->wep_restrict)
 			erq->flags |= IW_ENCODE_RESTRICTED;
 		else
@@ -2099,10 +2403,10 @@
 	erq->length = xlen;
 
 	if (erq->pointer) {
-		memcpy(keybuf, priv->keys[index].data, MAX_KEY_SIZE);
+		memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE);
 	}
 	
-	dldwd_unlock(priv);
+	orinoco_unlock(priv);
 
 	if (erq->pointer) {
 		if (copy_to_user(erq->pointer, keybuf, xlen))
@@ -2112,9 +2416,9 @@
 	return 0;
 }
 
-static int dldwd_ioctl_setessid(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_setessid(struct net_device *dev, struct iw_point *erq)
 {
-	dldwd_priv_t *priv = dev->priv;
+	struct orinoco_private *priv = dev->priv;
 	char essidbuf[IW_ESSID_MAX_SIZE+1];
 
 	/* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it
@@ -2132,27 +2436,33 @@
 		essidbuf[erq->length] = '\0';
 	}
 
-	dldwd_lock(priv);
+	orinoco_lock(priv);
 
 	memcpy(priv->desired_essid, essidbuf, sizeof(priv->desired_essid));
 
-	dldwd_unlock(priv);
+	orinoco_unlock(priv);
 
 	return 0;
 }
 
-static int dldwd_ioctl_getessid(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq)
 {
-	dldwd_priv_t *priv = dev->priv;
+	struct orinoco_private *priv = dev->priv;
 	char essidbuf[IW_ESSID_MAX_SIZE+1];
 	int active;
 	int err = 0;
 
 	TRACE_ENTER(dev->name);
 
-	err = dldwd_hw_get_essid(priv, &active, essidbuf);
-	if (err)
-		return err;
+	if (netif_running(dev)) {
+		err = orinoco_hw_get_essid(priv, &active, essidbuf);
+		if (err)
+			return err;
+	} else {
+		orinoco_lock(priv);
+		memcpy(essidbuf, priv->desired_essid, sizeof(essidbuf));
+		orinoco_unlock(priv);
+	}
 
 	erq->flags = 1;
 	erq->length = strlen(essidbuf) + 1;
@@ -2165,9 +2475,9 @@
 	return 0;
 }
 
-static int dldwd_ioctl_setnick(struct net_device *dev, struct iw_point *nrq)
+static int orinoco_ioctl_setnick(struct net_device *dev, struct iw_point *nrq)
 {
-	dldwd_priv_t *priv = dev->priv;
+	struct orinoco_private *priv = dev->priv;
 	char nickbuf[IW_ESSID_MAX_SIZE+1];
 
 	if (nrq->length > IW_ESSID_MAX_SIZE)
@@ -2180,23 +2490,23 @@
 
 	nickbuf[nrq->length] = '\0';
 	
-	dldwd_lock(priv);
+	orinoco_lock(priv);
 
 	memcpy(priv->nick, nickbuf, sizeof(priv->nick));
 
-	dldwd_unlock(priv);
+	orinoco_unlock(priv);
 
 	return 0;
 }
 
-static int dldwd_ioctl_getnick(struct net_device *dev, struct iw_point *nrq)
+static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq)
 {
-	dldwd_priv_t *priv = dev->priv;
+	struct orinoco_private *priv = dev->priv;
 	char nickbuf[IW_ESSID_MAX_SIZE+1];
 
-	dldwd_lock(priv);
+	orinoco_lock(priv);
 	memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE+1);
-	dldwd_unlock(priv);
+	orinoco_unlock(priv);
 
 	nrq->length = strlen(nickbuf)+1;
 
@@ -2206,9 +2516,9 @@
 	return 0;
 }
 
-static int dldwd_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq)
+static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq)
 {
-	dldwd_priv_t *priv = dev->priv;
+	struct orinoco_private *priv = dev->priv;
 	int chan = -1;
 
 	/* We can only use this in Ad-Hoc demo mode to set the operating
@@ -2237,23 +2547,26 @@
 	     ! (priv->channel_mask & (1 << (chan-1)) ) )
 		return -EINVAL;
 
-	dldwd_lock(priv);
+	orinoco_lock(priv);
 	priv->channel = chan;
-	dldwd_unlock(priv);
+	orinoco_unlock(priv);
 
 	return 0;
 }
 
-static int dldwd_ioctl_getsens(struct net_device *dev, struct iw_param *srq)
+static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq)
 {
-	dldwd_priv_t *priv = dev->priv;
+	struct orinoco_private *priv = dev->priv;
 	hermes_t *hw = &priv->hw;
 	u16 val;
 	int err;
 
-	dldwd_lock(priv);
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, &val);
-	dldwd_unlock(priv);
+	if (!priv->has_sensitivity)
+		return -EOPNOTSUPP;
+
+	orinoco_lock(priv);
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE, &val);
+	orinoco_unlock(priv);
 
 	if (err)
 		return err;
@@ -2264,24 +2577,27 @@
 	return 0;
 }
 
-static int dldwd_ioctl_setsens(struct net_device *dev, struct iw_param *srq)
+static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq)
 {
-	dldwd_priv_t *priv = dev->priv;
+	struct orinoco_private *priv = dev->priv;
 	int val = srq->value;
 
+	if (!priv->has_sensitivity)
+		return -EOPNOTSUPP;
+
 	if ((val < 1) || (val > 3))
 		return -EINVAL;
 	
-	dldwd_lock(priv);
+	orinoco_lock(priv);
 	priv->ap_density = val;
-	dldwd_unlock(priv);
+	orinoco_unlock(priv);
 
 	return 0;
 }
 
-static int dldwd_ioctl_setrts(struct net_device *dev, struct iw_param *rrq)
+static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq)
 {
-	dldwd_priv_t *priv = dev->priv;
+	struct orinoco_private *priv = dev->priv;
 	int val = rrq->value;
 
 	if (rrq->disabled)
@@ -2290,19 +2606,19 @@
 	if ( (val < 0) || (val > 2347) )
 		return -EINVAL;
 
-	dldwd_lock(priv);
+	orinoco_lock(priv);
 	priv->rts_thresh = val;
-	dldwd_unlock(priv);
+	orinoco_unlock(priv);
 
 	return 0;
 }
 
-static int dldwd_ioctl_setfrag(struct net_device *dev, struct iw_param *frq)
+static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq)
 {
-	dldwd_priv_t *priv = dev->priv;
+	struct orinoco_private *priv = dev->priv;
 	int err = 0;
 
-	dldwd_lock(priv);
+	orinoco_lock(priv);
 
 	if (priv->has_mwo) {
 		if (frq->disabled)
@@ -2324,22 +2640,24 @@
 		}
 	}
 
-	dldwd_unlock(priv);
+	orinoco_unlock(priv);
 
 	return err;
 }
 
-static int dldwd_ioctl_getfrag(struct net_device *dev, struct iw_param *frq)
+static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq)
 {
-	dldwd_priv_t *priv = dev->priv;
+	struct orinoco_private *priv = dev->priv;
 	hermes_t *hw = &priv->hw;
 	int err = 0;
 	u16 val;
 
-	dldwd_lock(priv);
+	orinoco_lock(priv);
 	
 	if (priv->has_mwo) {
-		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_MWO_ROBUST, &val);
+		err = hermes_read_wordrec(hw, USER_BAP,
+					  HERMES_RID_CNFMWOROBUST_AGERE,
+					  &val);
 		if (err)
 			val = 0;
 
@@ -2347,7 +2665,8 @@
 		frq->disabled = ! val;
 		frq->fixed = 0;
 	} else {
-		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_FRAG_THRESH, &val);
+		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
+					  &val);
 		if (err)
 			val = 0;
 
@@ -2356,158 +2675,122 @@
 		frq->fixed = 1;
 	}
 
-	dldwd_unlock(priv);
+	orinoco_unlock(priv);
 	
 	return err;
 }
 
-static int dldwd_ioctl_setrate(struct net_device *dev, struct iw_param *rrq)
+static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *rrq)
 {
-	dldwd_priv_t *priv = dev->priv;
+	struct orinoco_private *priv = dev->priv;
 	int err = 0;
-	int rate_ctrl = -1;
-	int fixed, upto;
-	int brate;
+	int ratemode = -1;
+	int bitrate; /* 100s of kilobits */
 	int i;
+	
+	/* As the user space doesn't know our highest rate, it uses -1
+	 * to ask us to set the highest rate.  Test it using "iwconfig
+	 * ethX rate auto" - Jean II */
+	if (rrq->value == -1)
+		bitrate = 110;
+	else {
+		if (rrq->value % 100000)
+			return -EINVAL;
+		bitrate = rrq->value / 100000;
+	}
 
-	dldwd_lock(priv);
-
-	/* Normalise value */
-	brate = rrq->value / 500000;
+	if ( (bitrate != 10) && (bitrate != 20) &&
+	     (bitrate != 55) && (bitrate != 110) )
+		return -EINVAL;
 
-	switch (priv->firmware_type) {
-	case FIRMWARE_TYPE_LUCENT: /* Lucent style rate */
-		if (! rrq->fixed) {
-			if (brate > 0)
-				brate = -brate;
-			else
-				brate = -22;
-		}
-	
-		for (i = 0; i < NUM_RATES; i++)
-			if (rate_list[i] == brate) {
-				rate_ctrl = i;
-				break;
-			}
-	
-		if ( (rate_ctrl < 1) || (rate_ctrl >= NUM_RATES) )
-			err = -EINVAL;
-		else
-			priv->tx_rate_ctrl = rate_ctrl;
-		break;
-	case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */
-	case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */
-		switch(brate) {
-		case 0:
-			fixed = 0x0;
-			upto = 0xF;
-			break;
-		case 2:
-			fixed = 0x1;
-			upto = 0x1;
-			break;
-		case 4:
-			fixed = 0x2;
-			upto = 0x3;
-			break;
-		case 11:
-			fixed = 0x4;
-			upto = 0x7;
-			break;
-		case 22:
-			fixed = 0x8;
-			upto = 0xF;
+	for (i = 0; i < BITRATE_TABLE_SIZE; i++)
+		if ( (bitrate_table[i].bitrate == bitrate) &&
+		     (bitrate_table[i].automatic == ! rrq->fixed) ) {
+			ratemode = i;
 			break;
-		default:
-			fixed = 0x0;
-			upto = 0x0;
 		}
-		if (rrq->fixed)
-			rate_ctrl = fixed;
-		else
-			rate_ctrl = upto;
-		if (rate_ctrl == 0)
-			err = -EINVAL;
-		else
-			priv->tx_rate_ctrl = rate_ctrl;
-		break;
-	}
+	
+	if (ratemode == -1)
+		return -EINVAL;
 
-	dldwd_unlock(priv);
+	orinoco_lock(priv);
+	priv->bitratemode = ratemode;
+	orinoco_unlock(priv);
 
 	return err;
 }
 
-static int dldwd_ioctl_getrate(struct net_device *dev, struct iw_param *rrq)
+static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *rrq)
 {
-	dldwd_priv_t *priv = dev->priv;
+	struct orinoco_private *priv = dev->priv;
 	hermes_t *hw = &priv->hw;
 	int err = 0;
+	int ratemode;
+	int i;
 	u16 val;
-	int brate = 0;
 
-	dldwd_lock(priv);
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_RATE_CTRL, &val);
-	if (err)
-		goto out;
-	
-	switch (priv->firmware_type) {
-	case FIRMWARE_TYPE_LUCENT: /* Lucent style rate */
-		brate = rate_list[val];
-	
-		if (brate < 0) {
-			rrq->fixed = 0;
+	orinoco_lock(priv);
 
-			err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_TX_RATE, &val);
-			if (err)
-				goto out;
+	ratemode = priv->bitratemode;
+
+	if ( (ratemode < 0) || (ratemode > BITRATE_TABLE_SIZE) )
+		BUG();
+
+	rrq->value = bitrate_table[ratemode].bitrate * 100000;
+	rrq->fixed = ! bitrate_table[ratemode].automatic;
+	rrq->disabled = 0;
 
+	/* If the interface is running we try to find more about the
+	   current mode */
+	if (netif_running(dev)) {
+		err = hermes_read_wordrec(hw, USER_BAP,
+					  HERMES_RID_CURRENTTXRATE, &val);
+		if (err)
+			goto out;
+		
+		switch (priv->firmware_type) {
+		case FIRMWARE_TYPE_AGERE: /* Lucent style rate */
+			/* Note : in Lucent firmware, the return value of
+			 * HERMES_RID_CURRENTTXRATE is the bitrate in Mb/s,
+			 * and therefore is totally different from the
+			 * encoding of HERMES_RID_CNFTXRATECONTROL.
+			 * Don't forget that 6Mb/s is really 5.5Mb/s */
 			if (val == 6)
-				brate = 11;
+				rrq->value = 5500000;
 			else
-				brate = 2*val;
-		} else
-			rrq->fixed = 1;
-		break;
-	case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */
-	case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */
-		/* Check if auto or fixed (crude approximation) */
-		if((val & 0x1) && (val > 1)) {
-			rrq->fixed = 0;
-
-			err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_TX_RATE, &val);
-			if (err)
-				goto out;
-		} else
-			rrq->fixed = 1;
+				rrq->value = val * 1000000;
+                        break;
+		case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */
+		case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */
+			for (i = 0; i < BITRATE_TABLE_SIZE; i++)
+				if (bitrate_table[i].intersil_txratectrl == val) {
+					ratemode = i;
+					break;
+				}
+			if (i >= BITRATE_TABLE_SIZE)
+				printk(KERN_INFO "%s: Unable to determine current bitrate (0x%04hx)\n",
+				       dev->name, val);
 
-		if(val >= 8)
-			brate = 22;
-		else if(val >= 4)
-			brate = 11;
-		else if(val >= 2)
-			brate = 4;
-		else
-			brate = 2;
-		break;
+			rrq->value = bitrate_table[ratemode].bitrate * 100000;
+			break;
+		default:
+			BUG();
+		}
 	}
 
-	rrq->value = brate * 500000;
-	rrq->disabled = 0;
-
  out:
-	dldwd_unlock(priv);
+	orinoco_unlock(priv);
 
 	return err;
 }
 
-static int dldwd_ioctl_setpower(struct net_device *dev, struct iw_param *prq)
+static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq)
 {
-	dldwd_priv_t *priv = dev->priv;
+	struct orinoco_private *priv = dev->priv;
 	int err = 0;
 
 
-	dldwd_lock(priv);
+	orinoco_lock(priv);
 
 	if (prq->disabled) {
 		priv->pm_on = 0;
@@ -2547,33 +2830,34 @@
 	}
 
  out:
-	dldwd_unlock(priv);
+	orinoco_unlock(priv);
 
 	return err;
 }
 
-static int dldwd_ioctl_getpower(struct net_device *dev, struct iw_param *prq)
+static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq)
 {
-	dldwd_priv_t *priv = dev->priv;
+	struct orinoco_private *priv = dev->priv;
 	hermes_t *hw = &priv->hw;
 	int err = 0;
 	u16 enable, period, timeout, mcast;
 
-	dldwd_lock(priv);
+	orinoco_lock(priv);
 	
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_ENABLE, &enable);
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFPMENABLED, &enable);
 	if (err)
 		goto out;
 
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, &period);
+	err = hermes_read_wordrec(hw, USER_BAP,
+				  HERMES_RID_CNFMAXSLEEPDURATION, &period);
 	if (err)
 		goto out;
 
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER, &timeout);
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFPMHOLDOVERDURATION, &timeout);
 	if (err)
 		goto out;
 
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_MCAST_RX, &mcast);
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFMULTICASTRECEIVE, &mcast);
 	if (err)
 		goto out;
 
@@ -2592,30 +2876,33 @@
 		prq->flags |= IW_POWER_UNICAST_R;
 
  out:
-	dldwd_unlock(priv);
+	orinoco_unlock(priv);
 
 	return err;
 }
 
 #if WIRELESS_EXT > 10
-static int dldwd_ioctl_getretry(struct net_device *dev, struct iw_param *rrq)
+static int orinoco_ioctl_getretry(struct net_device *dev, struct iw_param *rrq)
 {
-	dldwd_priv_t *priv = dev->priv;
+	struct orinoco_private *priv = dev->priv;
 	hermes_t *hw = &priv->hw;
 	int err = 0;
 	u16 short_limit, long_limit, lifetime;
 
-	dldwd_lock(priv);
+	orinoco_lock(priv);
 	
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORT_RETRY_LIMIT, &short_limit);
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORTRETRYLIMIT,
+				  &short_limit);
 	if (err)
 		goto out;
 
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONG_RETRY_LIMIT, &long_limit);
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONGRETRYLIMIT,
+				  &long_limit);
 	if (err)
 		goto out;
 
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAX_TX_LIFETIME, &lifetime);
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAXTRANSMITLIFETIME,
+				  &lifetime);
 	if (err)
 		goto out;
 
@@ -2639,46 +2926,46 @@
 	}
 
  out:
-	dldwd_unlock(priv);
+	orinoco_unlock(priv);
 
 	return err;
 }
 #endif /* WIRELESS_EXT > 10 */
 
-static int dldwd_ioctl_setibssport(struct net_device *dev, struct iwreq *wrq)
+static int orinoco_ioctl_setibssport(struct net_device *dev, struct iwreq *wrq)
 {
-	dldwd_priv_t *priv = dev->priv;
+	struct orinoco_private *priv = dev->priv;
 	int val = *( (int *) wrq->u.name );
 
-	dldwd_lock(priv);
+	orinoco_lock(priv);
 	priv->ibss_port = val ;
 
 	/* Actually update the mode we are using */
 	set_port_type(priv);
 
-	dldwd_unlock(priv);
+	orinoco_unlock(priv);
 	return 0;
 }
 
-static int dldwd_ioctl_getibssport(struct net_device *dev, struct iwreq *wrq)
+static int orinoco_ioctl_getibssport(struct net_device *dev, struct iwreq *wrq)
 {
-	dldwd_priv_t *priv = dev->priv;
+	struct orinoco_private *priv = dev->priv;
 	int *val = (int *)wrq->u.name;
 
-	dldwd_lock(priv);
+	orinoco_lock(priv);
 	*val = priv->ibss_port;
-	dldwd_unlock(priv);
+	orinoco_unlock(priv);
 
 	return 0;
 }
 
-static int dldwd_ioctl_setport3(struct net_device *dev, struct iwreq *wrq)
+static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq)
 {
-	dldwd_priv_t *priv = dev->priv;
+	struct orinoco_private *priv = dev->priv;
 	int val = *( (int *) wrq->u.name );
 	int err = 0;
 
-	dldwd_lock(priv);
+	orinoco_lock(priv);
 	switch (val) {
 	case 0: /* Try to do IEEE ad-hoc mode */
 		if (! priv->has_ibss) {
@@ -2707,28 +2994,28 @@
 		/* Actually update the mode we are using */
 		set_port_type(priv);
 
-	dldwd_unlock(priv);
+	orinoco_unlock(priv);
 
 	return err;
 }
 
-static int dldwd_ioctl_getport3(struct net_device *dev, struct iwreq *wrq)
+static int orinoco_ioctl_getport3(struct net_device *dev, struct iwreq *wrq)
 {
-	dldwd_priv_t *priv = dev->priv;
+	struct orinoco_private *priv = dev->priv;
 	int *val = (int *)wrq->u.name;
 
-	dldwd_lock(priv);
+	orinoco_lock(priv);
 	*val = priv->prefer_port3;
-	dldwd_unlock(priv);
+	orinoco_unlock(priv);
 
 	return 0;
 }
 
 /* Spy is used for link quality/strength measurements in Ad-Hoc mode
  * Jean II */
-static int dldwd_ioctl_setspy(struct net_device *dev, struct iw_point *srq)
+static int orinoco_ioctl_setspy(struct net_device *dev, struct iw_point *srq)
 {
-	dldwd_priv_t *priv = dev->priv;
+	struct orinoco_private *priv = dev->priv;
 	struct sockaddr address[IW_MAX_SPY];
 	int number = srq->length;
 	int i;
@@ -2746,9 +3033,9 @@
 	}
 
 	/* Make sure nobody mess with the structure while we do */
-	dldwd_lock(priv);
+	orinoco_lock(priv);
 
-	/* dldwd_lock() doesn't disable interrupts, so make sure the
+	/* orinoco_lock() doesn't disable interrupts, so make sure the
 	 * interrupt rx path don't get confused while we copy */
 	priv->spy_number = 0;
 
@@ -2775,20 +3062,20 @@
 	}
 
 	/* Now, let the others play */
-	dldwd_unlock(priv);
+	orinoco_unlock(priv);
 
 	return err;
 }
 
-static int dldwd_ioctl_getspy(struct net_device *dev, struct iw_point *srq)
+static int orinoco_ioctl_getspy(struct net_device *dev, struct iw_point *srq)
 {
-	dldwd_priv_t *priv = dev->priv;
+	struct orinoco_private *priv = dev->priv;
 	struct sockaddr address[IW_MAX_SPY];
 	struct iw_quality spy_stat[IW_MAX_SPY];
 	int number;
 	int i;
 
-	dldwd_lock(priv);
+	orinoco_lock(priv);
 
 	number = priv->spy_number;
 	if ((number > 0) && (srq->pointer)) {
@@ -2808,7 +3095,7 @@
 			priv->spy_stat[i].updated = 0;
 	}
 
-	dldwd_unlock(priv);
+	orinoco_unlock(priv);
 
 	/* Push stuff to user space */
 	srq->length = number;
@@ -2822,23 +3109,23 @@
 	return 0;
 }
 
-int
-dldwd_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static int
+orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	dldwd_priv_t *priv = dev->priv;
+	struct orinoco_private *priv = dev->priv;
 	struct iwreq *wrq = (struct iwreq *)rq;
 	int err = 0;
 	int changed = 0;
 
 	TRACE_ENTER(dev->name);
 
-	/* In theory, we could allow most of the the SET stuff to be done
-	 * In practice, the laps of time at startup when the card is not
-	 * ready is very short, so why bother...
-	 * Note that hw_ready is different from up/down (ifconfig), when
-	 * the device is not yet up, it is usually already ready...
-	 * Jean II */
-	if (!priv->hw_ready)
+	/* In theory, we could allow most of the the SET stuff to be
+	 * done In practice, the laps of time at startup when the card
+	 * is not ready is very short, so why bother...  Note that
+	 * netif_device_present is different from up/down (ifconfig),
+	 * when the device is not yet up, it is usually already
+	 * ready...  Jean II */
+	if (! netif_device_present(dev))
 		return -ENODEV;
 
 	switch (cmd) {
@@ -2850,17 +3137,17 @@
 	case SIOCGIWAP:
 		DEBUG(1, "%s: SIOCGIWAP\n", dev->name);
 		wrq->u.ap_addr.sa_family = ARPHRD_ETHER;
-		err = dldwd_hw_get_bssid(priv, wrq->u.ap_addr.sa_data);
+		err = orinoco_hw_get_bssid(priv, wrq->u.ap_addr.sa_data);
 		break;
 
 	case SIOCGIWRANGE:
 		DEBUG(1, "%s: SIOCGIWRANGE\n", dev->name);
-		err = dldwd_ioctl_getiwrange(dev, &wrq->u.data);
+		err = orinoco_ioctl_getiwrange(dev, &wrq->u.data);
 		break;
 
 	case SIOCSIWMODE:
 		DEBUG(1, "%s: SIOCSIWMODE\n", dev->name);
-		dldwd_lock(priv);
+		orinoco_lock(priv);
 		switch (wrq->u.mode) {
 		case IW_MODE_ADHOC:
 			if (! (priv->has_ibss || priv->has_port3) )
@@ -2881,14 +3168,14 @@
 			break;
 		}
 		set_port_type(priv);
-		dldwd_unlock(priv);
+		orinoco_unlock(priv);
 		break;
 
 	case SIOCGIWMODE:
 		DEBUG(1, "%s: SIOCGIWMODE\n", dev->name);
-		dldwd_lock(priv);
+		orinoco_lock(priv);
 		wrq->u.mode = priv->iw_mode;
-		dldwd_unlock(priv);
+		orinoco_unlock(priv);
 		break;
 
 	case SIOCSIWENCODE:
@@ -2898,7 +3185,7 @@
 			break;
 		}
 
-		err = dldwd_ioctl_setiwencode(dev, &wrq->u.encoding);
+		err = orinoco_ioctl_setiwencode(dev, &wrq->u.encoding);
 		if (! err)
 			changed = 1;
 		break;
@@ -2915,54 +3202,54 @@
 			break;
 		}
 
-		err = dldwd_ioctl_getiwencode(dev, &wrq->u.encoding);
+		err = orinoco_ioctl_getiwencode(dev, &wrq->u.encoding);
 		break;
 
 	case SIOCSIWESSID:
 		DEBUG(1, "%s: SIOCSIWESSID\n", dev->name);
-		err = dldwd_ioctl_setessid(dev, &wrq->u.essid);
+		err = orinoco_ioctl_setessid(dev, &wrq->u.essid);
 		if (! err)
 			changed = 1;
 		break;
 
 	case SIOCGIWESSID:
 		DEBUG(1, "%s: SIOCGIWESSID\n", dev->name);
-		err = dldwd_ioctl_getessid(dev, &wrq->u.essid);
+		err = orinoco_ioctl_getessid(dev, &wrq->u.essid);
 		break;
 
 	case SIOCSIWNICKN:
 		DEBUG(1, "%s: SIOCSIWNICKN\n", dev->name);
-		err = dldwd_ioctl_setnick(dev, &wrq->u.data);
+		err = orinoco_ioctl_setnick(dev, &wrq->u.data);
 		if (! err)
 			changed = 1;
 		break;
 
 	case SIOCGIWNICKN:
 		DEBUG(1, "%s: SIOCGIWNICKN\n", dev->name);
-		err = dldwd_ioctl_getnick(dev, &wrq->u.data);
+		err = orinoco_ioctl_getnick(dev, &wrq->u.data);
 		break;
 
 	case SIOCGIWFREQ:
 		DEBUG(1, "%s: SIOCGIWFREQ\n", dev->name);
-		wrq->u.freq.m = dldwd_hw_get_freq(priv);
+		wrq->u.freq.m = orinoco_hw_get_freq(priv);
 		wrq->u.freq.e = 1;
 		break;
 
 	case SIOCSIWFREQ:
 		DEBUG(1, "%s: SIOCSIWFREQ\n", dev->name);
-		err = dldwd_ioctl_setfreq(dev, &wrq->u.freq);
+		err = orinoco_ioctl_setfreq(dev, &wrq->u.freq);
 		if (! err)
 			changed = 1;
 		break;
 
 	case SIOCGIWSENS:
 		DEBUG(1, "%s: SIOCGIWSENS\n", dev->name);
-		err = dldwd_ioctl_getsens(dev, &wrq->u.sens);
+		err = orinoco_ioctl_getsens(dev, &wrq->u.sens);
 		break;
 
 	case SIOCSIWSENS:
 		DEBUG(1, "%s: SIOCSIWSENS\n", dev->name);
-		err = dldwd_ioctl_setsens(dev, &wrq->u.sens);
+		err = orinoco_ioctl_setsens(dev, &wrq->u.sens);
 		if (! err)
 			changed = 1;
 		break;
@@ -2976,45 +3263,45 @@
 
 	case SIOCSIWRTS:
 		DEBUG(1, "%s: SIOCSIWRTS\n", dev->name);
-		err = dldwd_ioctl_setrts(dev, &wrq->u.rts);
+		err = orinoco_ioctl_setrts(dev, &wrq->u.rts);
 		if (! err)
 			changed = 1;
 		break;
 
 	case SIOCSIWFRAG:
 		DEBUG(1, "%s: SIOCSIWFRAG\n", dev->name);
-		err = dldwd_ioctl_setfrag(dev, &wrq->u.frag);
+		err = orinoco_ioctl_setfrag(dev, &wrq->u.frag);
 		if (! err)
 			changed = 1;
 		break;
 
 	case SIOCGIWFRAG:
 		DEBUG(1, "%s: SIOCGIWFRAG\n", dev->name);
-		err = dldwd_ioctl_getfrag(dev, &wrq->u.frag);
+		err = orinoco_ioctl_getfrag(dev, &wrq->u.frag);
 		break;
 
 	case SIOCSIWRATE:
 		DEBUG(1, "%s: SIOCSIWRATE\n", dev->name);
-		err = dldwd_ioctl_setrate(dev, &wrq->u.bitrate);
+		err = orinoco_ioctl_setrate(dev, &wrq->u.bitrate);
 		if (! err)
 			changed = 1;
 		break;
 
 	case SIOCGIWRATE:
 		DEBUG(1, "%s: SIOCGIWRATE\n", dev->name);
-		err = dldwd_ioctl_getrate(dev, &wrq->u.bitrate);
+		err = orinoco_ioctl_getrate(dev, &wrq->u.bitrate);
 		break;
 
 	case SIOCSIWPOWER:
 		DEBUG(1, "%s: SIOCSIWPOWER\n", dev->name);
-		err = dldwd_ioctl_setpower(dev, &wrq->u.power);
+		err = orinoco_ioctl_setpower(dev, &wrq->u.power);
 		if (! err)
 			changed = 1;
 		break;
 
 	case SIOCGIWPOWER:
 		DEBUG(1, "%s: SIOCGIWPOWER\n", dev->name);
-		err = dldwd_ioctl_getpower(dev, &wrq->u.power);
+		err = orinoco_ioctl_getpower(dev, &wrq->u.power);
 		break;
 
 	case SIOCGIWTXPOW:
@@ -3034,44 +3321,44 @@
 
 	case SIOCGIWRETRY:
 		DEBUG(1, "%s: SIOCGIWRETRY\n", dev->name);
-		err = dldwd_ioctl_getretry(dev, &wrq->u.retry);
+		err = orinoco_ioctl_getretry(dev, &wrq->u.retry);
 		break;
 #endif /* WIRELESS_EXT > 10 */
 
 	case SIOCSIWSPY:
 		DEBUG(1, "%s: SIOCSIWSPY\n", dev->name);
 
-		err = dldwd_ioctl_setspy(dev, &wrq->u.data);
+		err = orinoco_ioctl_setspy(dev, &wrq->u.data);
 		break;
 
 	case SIOCGIWSPY:
 		DEBUG(1, "%s: SIOCGIWSPY\n", dev->name);
 
-		err = dldwd_ioctl_getspy(dev, &wrq->u.data);
+		err = orinoco_ioctl_getspy(dev, &wrq->u.data);
 		break;
 
 	case SIOCGIWPRIV:
 		DEBUG(1, "%s: SIOCGIWPRIV\n", dev->name);
 		if (wrq->u.data.pointer) {
 			struct iw_priv_args privtab[] = {
-				{ SIOCDEVPRIVATE + 0x0, 0, 0, "force_reset" },
-				{ SIOCDEVPRIVATE + 0x1, 0, 0, "card_reset" },
-				{ SIOCDEVPRIVATE + 0x2,
+				{ SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" },
+				{ SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" },
+				{ SIOCIWFIRSTPRIV + 0x2,
 				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
 				  0, "set_port3" },
-				{ SIOCDEVPRIVATE + 0x3, 0,
+				{ SIOCIWFIRSTPRIV + 0x3, 0,
 				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
 				  "get_port3" },
-				{ SIOCDEVPRIVATE + 0x4,
+				{ SIOCIWFIRSTPRIV + 0x4,
 				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
 				  0, "set_preamble" },
-				{ SIOCDEVPRIVATE + 0x5, 0,
+				{ SIOCIWFIRSTPRIV + 0x5, 0,
 				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
 				  "get_preamble" },
-				{ SIOCDEVPRIVATE + 0x6,
+				{ SIOCIWFIRSTPRIV + 0x6,
 				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
 				  0, "set_ibssport" },
-				{ SIOCDEVPRIVATE + 0x7, 0,
+				{ SIOCIWFIRSTPRIV + 0x7, 0,
 				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
 				  "get_ibssport" }
 			};
@@ -3086,8 +3373,9 @@
 		}
 		break;
 	       
-	case SIOCDEVPRIVATE + 0x0: /* force_reset */
-		DEBUG(1, "%s: SIOCDEVPRIVATE + 0x0 (force_reset)\n",
+	case SIOCIWFIRSTPRIV + 0x0: /* force_reset */
+	case SIOCIWFIRSTPRIV + 0x1: /* card_reset */
+		DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x0 (force_reset)\n",
 		      dev->name);
 		if (! capable(CAP_NET_ADMIN)) {
 			err = -EPERM;
@@ -3095,44 +3383,35 @@
 		}
 		
 		printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name);
-		dldwd_reset(priv);
-		break;
 
-	case SIOCDEVPRIVATE + 0x1: /* card_reset */
-		DEBUG(1, "%s: SIOCDEVPRIVATE + 0x1 (card_reset)\n",
-		      dev->name);
-		if (! capable(CAP_NET_ADMIN)) {
-			err = -EPERM;
-			break;
-		}
-		
-		printk(KERN_DEBUG "%s: Forcing card reset!\n", dev->name);
-		if(priv->card_reset_handler != NULL)
-			priv->card_reset_handler(priv);
-		dldwd_reset(priv);
+		/* We need the xmit lock because it protects the
+		   multicast list which orinoco_reset() reads */
+		spin_lock_bh(&dev->xmit_lock);
+		orinoco_reset(priv);
+		spin_unlock_bh(&dev->xmit_lock);
 		break;
 
-	case SIOCDEVPRIVATE + 0x2: /* set_port3 */
-		DEBUG(1, "%s: SIOCDEVPRIVATE + 0x2 (set_port3)\n",
+	case SIOCIWFIRSTPRIV + 0x2: /* set_port3 */
+		DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x2 (set_port3)\n",
 		      dev->name);
 		if (! capable(CAP_NET_ADMIN)) {
 			err = -EPERM;
 			break;
 		}
 
-		err = dldwd_ioctl_setport3(dev, wrq);
+		err = orinoco_ioctl_setport3(dev, wrq);
 		if (! err)
 			changed = 1;
 		break;
 
-	case SIOCDEVPRIVATE + 0x3: /* get_port3 */
-		DEBUG(1, "%s: SIOCDEVPRIVATE + 0x3 (get_port3)\n",
+	case SIOCIWFIRSTPRIV + 0x3: /* get_port3 */
+		DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x3 (get_port3)\n",
 		      dev->name);
-		err = dldwd_ioctl_getport3(dev, wrq);
+		err = orinoco_ioctl_getport3(dev, wrq);
 		break;
 
-	case SIOCDEVPRIVATE + 0x4: /* set_preamble */
-		DEBUG(1, "%s: SIOCDEVPRIVATE + 0x4 (set_preamble)\n",
+	case SIOCIWFIRSTPRIV + 0x4: /* set_preamble */
+		DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x4 (set_preamble)\n",
 		      dev->name);
 		if (! capable(CAP_NET_ADMIN)) {
 			err = -EPERM;
@@ -3147,46 +3426,46 @@
 		if(priv->has_preamble) {
 			int val = *( (int *) wrq->u.name );
 
-			dldwd_lock(priv);
+			orinoco_lock(priv);
 			if(val)
 				priv->preamble = 1;
 			else
 				priv->preamble = 0;
-			dldwd_unlock(priv);
+			orinoco_unlock(priv);
 			changed = 1;
 		} else
 			err = -EOPNOTSUPP;
 		break;
 
-	case SIOCDEVPRIVATE + 0x5: /* get_preamble */
-		DEBUG(1, "%s: SIOCDEVPRIVATE + 0x5 (get_preamble)\n",
+	case SIOCIWFIRSTPRIV + 0x5: /* get_preamble */
+		DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x5 (get_preamble)\n",
 		      dev->name);
 		if(priv->has_preamble) {
 			int *val = (int *)wrq->u.name;
 
-			dldwd_lock(priv);
+			orinoco_lock(priv);
 			*val = priv->preamble;
-			dldwd_unlock(priv);
+			orinoco_unlock(priv);
 		} else
 			err = -EOPNOTSUPP;
 		break;
-	case SIOCDEVPRIVATE + 0x6: /* set_ibssport */
-		DEBUG(1, "%s: SIOCDEVPRIVATE + 0x6 (set_ibssport)\n",
+	case SIOCIWFIRSTPRIV + 0x6: /* set_ibssport */
+		DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x6 (set_ibssport)\n",
 		      dev->name);
 		if (! capable(CAP_NET_ADMIN)) {
 			err = -EPERM;
 			break;
 		}
 
-		err = dldwd_ioctl_setibssport(dev, wrq);
+		err = orinoco_ioctl_setibssport(dev, wrq);
 		if (! err)
 			changed = 1;
 		break;
 
-	case SIOCDEVPRIVATE + 0x7: /* get_ibssport */
-		DEBUG(1, "%s: SIOCDEVPRIVATE + 0x7 (get_ibssport)\n",
+	case SIOCIWFIRSTPRIV + 0x7: /* get_ibssport */
+		DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x7 (get_ibssport)\n",
 		      dev->name);
-		err = dldwd_ioctl_getibssport(dev, wrq);
+		err = orinoco_ioctl_getibssport(dev, wrq);
 		break;
 
 
@@ -3195,14 +3474,17 @@
 	}
 	
 	if (! err && changed && netif_running(dev)) {
-		err = dldwd_reset(priv);
+		/* We need the xmit lock because it protects the
+		   multicast list which orinoco_reset() reads */
+		spin_lock_bh(&dev->xmit_lock);
+		err = orinoco_reset(priv);
+		spin_unlock_bh(&dev->xmit_lock);
 		if (err) {
 			/* Ouch ! What are we supposed to do ? */
 			printk(KERN_ERR "orinoco_cs: Failed to set parameters on %s\n",
 			       dev->name);
-			netif_stop_queue(dev);
-			dldwd_shutdown(priv);
-			priv->hw_ready = 0;
+			netif_device_detach(dev);
+			orinoco_shutdown(priv);
 		}
 	}		
 
@@ -3211,147 +3493,14 @@
 	return err;
 }
 
-int
-dldwd_change_mtu(struct net_device *dev, int new_mtu)
-{
-	TRACE_ENTER(dev->name);
-
-	if ( (new_mtu < DLDWD_MIN_MTU) || (new_mtu > DLDWD_MAX_MTU) )
-		return -EINVAL;
-
-	dev->mtu = new_mtu;
-
-	TRACE_EXIT(dev->name);
-
-	return 0;
-}
-
-static void
-__dldwd_set_multicast_list(struct net_device *dev)
-{
-	dldwd_priv_t *priv = dev->priv;
-	hermes_t *hw = &priv->hw;
-	int err = 0;
-	int promisc, allmulti, mc_count;
-
-	/* We'll wait until it's ready. Anyway, the network doesn't call us
-	 * here until we are open - Jean II */
-	if (!priv->hw_ready)
-		return;
-
-
-	TRACE_ENTER(dev->name);
-
-	DEBUG(3, "dev->flags=0x%x, priv->promiscuous=%d, dev->mc_count=%d priv->mc_count=%d\n",
-	      dev->flags, priv->promiscuous, dev->mc_count, priv->mc_count);
-
-	/* The Hermes doesn't seem to have an allmulti mode, so we go
-	 * into promiscuous mode and let the upper levels deal. */
-	if ( (dev->flags & IFF_PROMISC) ) {
-		promisc = 1;
-		allmulti = 0;
-		mc_count = 0;
-	} else if ( (dev->flags & IFF_ALLMULTI) ||
-		    (dev->mc_count > HERMES_MAX_MULTICAST) ) {
-		promisc = 0;
-		allmulti = 1;
-		mc_count = HERMES_MAX_MULTICAST;
-	} else {
-		promisc = 0;
-		allmulti = 0;
-		mc_count = dev->mc_count;
-	}
-
-	DEBUG(3, "promisc=%d mc_count=%d\n",
-	      promisc, mc_count);
-
-	if (promisc != priv->promiscuous) { /* Don't touch the hardware if we don't have to */
-		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PROMISCUOUS,
-					   promisc);
-		if (err) {
-			printk(KERN_ERR "%s: Error %d setting promiscuity to %d.\n",
-			       dev->name, err, promisc);
-		} else 
-			priv->promiscuous = promisc;
-	}
-
-	if (allmulti) {
-		/* FIXME: This method of doing allmulticast reception
-		   comes from the NetBSD driver. Haven't actually
-		   tested whether it works or not. */
-		hermes_multicast_t mclist;
-
-		memset(&mclist, 0, sizeof(mclist));
-		err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNF_MULTICAST_LIST, &mclist);
-		if (err)
-			printk(KERN_ERR "%s: Error %d setting multicast list.\n",
-			       dev->name, err);
-		else
-			priv->allmulti = 1;
-		       
-	} else if (mc_count || (! mc_count && priv->mc_count) ) {
-		struct dev_mc_list *p = dev->mc_list;
-		hermes_multicast_t mclist;
-		int i;
-
-		for (i = 0; i < mc_count; i++) {
-			/* First some paranoid checks */
-			if (! p) {
-				printk(KERN_ERR "%s: Multicast list shorter than mc_count.\n",
-				       dev->name);
-				break;
-			}
-			if (p->dmi_addrlen != ETH_ALEN) {
-
-				printk(KERN_ERR "%s: Bad address size (%d) in multicast list.\n",
-				       dev->name, p->dmi_addrlen);
-				break;
-			}
-
-			memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN);
-			p = p->next;
-		}
-
-		/* More paranoia */
-		if (p)
-			printk(KERN_ERR "%s: Multicast list longer than mc_count.\n",
-			       dev->name);
-
-		priv->mc_count = i;			
-
-		DEBUG(3, "priv->mc_count = %d\n", priv->mc_count);
-
-		err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNF_MULTICAST_LIST,
-				       HERMES_BYTES_TO_RECLEN(priv->mc_count * ETH_ALEN),
-				       &mclist);
-		if (err)
-			printk(KERN_ERR "%s: Error %d setting multicast list.\n",
-			       dev->name, err);
-		else
-			priv->allmulti = 0;
-	}
-
-	/* Since we can set the promiscuous flag when it wasn't asked
-	   for, make sure the net_device knows about it. */
-	if (priv->promiscuous)
-		dev->flags |= IFF_PROMISC;
-	else
-		dev->flags &= ~IFF_PROMISC;
-
-	if (priv->allmulti)
-		dev->flags |= IFF_ALLMULTI;
-	else
-		dev->flags &= ~IFF_ALLMULTI;
-
-	TRACE_EXIT(dev->name);
-}
-
-/*
- * procfs stuff
- */
+/********************************************************************/
+/* procfs stuff                                                     */
+/********************************************************************/
 
 static struct proc_dir_entry *dir_base = NULL;
 
+#define PROC_LTV_SIZE		128
+
 /*
  * This function updates the total amount of data printed so far. It then
  * determines if the amount of data printed into a buffer  has reached the
@@ -3361,7 +3510,6 @@
  * function returns 1, otherwise 0.
  */
 static int 
-
 shift_buffer(char *buffer, int requested_offset, int requested_len,
 	     int *total, int *slop, char **buf)
 {
@@ -3420,153 +3568,161 @@
 	return return_len;
 }
 
-static int
-dldwd_proc_get_hermes_regs(char *page, char **start, off_t requested_offset,
-			   int requested_len, int *eof, void *data)
-{
-	dldwd_priv_t *dev = (dldwd_priv_t *)data;
-	hermes_t *hw = &dev->hw;
-	char *buf;
-	int total = 0, slop = 0;
-
-	/* Hum, in this case hardware register are probably not readable... */
-	if (!dev->hw_ready)
-		return -ENODEV;
-
-	buf = page;
-
-#define DHERMESREG(name) buf += sprintf(buf, "%-16s: %04x\n", #name, hermes_read_regn(hw, name))
-
-	DHERMESREG(CMD);
-	DHERMESREG(PARAM0);
-	DHERMESREG(PARAM1);
-	DHERMESREG(PARAM2);
-	DHERMESREG(STATUS);
-	DHERMESREG(RESP0);
-	DHERMESREG(RESP1);
-	DHERMESREG(RESP2);
-	DHERMESREG(INFOFID);
-	DHERMESREG(RXFID);
-	DHERMESREG(ALLOCFID);
-	DHERMESREG(TXCOMPLFID);
-	DHERMESREG(SELECT0);
-	DHERMESREG(OFFSET0);
-	DHERMESREG(SELECT1);
-	DHERMESREG(OFFSET1);
-	DHERMESREG(EVSTAT);
-	DHERMESREG(INTEN);
-	DHERMESREG(EVACK);
-	DHERMESREG(CONTROL);
-	DHERMESREG(SWSUPPORT0);
-	DHERMESREG(SWSUPPORT1);
-	DHERMESREG(SWSUPPORT2);
-	DHERMESREG(AUXPAGE);
-	DHERMESREG(AUXOFFSET);
-	DHERMESREG(AUXDATA);
-#undef DHERMESREG
-
-	shift_buffer(page, requested_offset, requested_len, &total,
-		     &slop, &buf);
-	return calc_start_len(page, start, requested_offset, requested_len,
-			      total, buf);
-}
-
 struct {
 	u16 rid;
 	char *name;
-	int minlen, maxlen;
 	int displaytype;
 #define DISPLAY_WORDS	0
 #define DISPLAY_BYTES	1
 #define DISPLAY_STRING	2
+#define DISPLAY_XSTRING	3
 } record_table[] = {
-#define RTCNFENTRY(name, type) { HERMES_RID_CNF_##name, #name, 0, LTV_BUF_SIZE, type }
-	RTCNFENTRY(PORTTYPE, DISPLAY_WORDS),
-	RTCNFENTRY(MACADDR, DISPLAY_BYTES),
-	RTCNFENTRY(DESIRED_SSID, DISPLAY_STRING),
-	RTCNFENTRY(CHANNEL, DISPLAY_WORDS),
-	RTCNFENTRY(OWN_SSID, DISPLAY_STRING),
-	RTCNFENTRY(SYSTEM_SCALE, DISPLAY_WORDS),
-	RTCNFENTRY(MAX_DATA_LEN, DISPLAY_WORDS),
-	RTCNFENTRY(PM_ENABLE, DISPLAY_WORDS),
-	RTCNFENTRY(PM_MCAST_RX, DISPLAY_WORDS),
-	RTCNFENTRY(PM_PERIOD, DISPLAY_WORDS),
-	RTCNFENTRY(NICKNAME, DISPLAY_STRING),
-	RTCNFENTRY(WEP_ON, DISPLAY_WORDS),
-	RTCNFENTRY(MWO_ROBUST, DISPLAY_WORDS),
-	RTCNFENTRY(MULTICAST_LIST, DISPLAY_BYTES),
-	RTCNFENTRY(CREATEIBSS, DISPLAY_WORDS),
-	RTCNFENTRY(FRAG_THRESH, DISPLAY_WORDS),
-	RTCNFENTRY(RTS_THRESH, DISPLAY_WORDS),
-	RTCNFENTRY(TX_RATE_CTRL, DISPLAY_WORDS),
-	RTCNFENTRY(PROMISCUOUS, DISPLAY_WORDS),
-	RTCNFENTRY(KEYS, DISPLAY_BYTES),
-	RTCNFENTRY(TX_KEY, DISPLAY_WORDS),
-	RTCNFENTRY(TICKTIME, DISPLAY_WORDS),
-	RTCNFENTRY(INTERSIL_TX_KEY, DISPLAY_WORDS),
-	RTCNFENTRY(INTERSIL_KEY0, DISPLAY_BYTES),
-	RTCNFENTRY(INTERSIL_KEY1, DISPLAY_BYTES),
-	RTCNFENTRY(INTERSIL_KEY2, DISPLAY_BYTES),
-	RTCNFENTRY(INTERSIL_KEY3, DISPLAY_BYTES),
-	RTCNFENTRY(INTERSIL_WEP_ON, DISPLAY_WORDS),
-#undef RTCNFENTRY
-#define RTINFENTRY(name,type) { HERMES_RID_##name, #name, 0, LTV_BUF_SIZE, type }
-	RTINFENTRY(CHANNEL_LIST, DISPLAY_WORDS),
-	RTINFENTRY(STAIDENTITY, DISPLAY_WORDS),
-	RTINFENTRY(CURRENT_SSID, DISPLAY_STRING),
-	RTINFENTRY(CURRENT_BSSID, DISPLAY_BYTES),
-	RTINFENTRY(COMMSQUALITY, DISPLAY_WORDS),
-	RTINFENTRY(CURRENT_TX_RATE, DISPLAY_WORDS),
-	RTINFENTRY(WEP_AVAIL, DISPLAY_WORDS),
-	RTINFENTRY(CURRENT_CHANNEL, DISPLAY_WORDS),
-	RTINFENTRY(DATARATES, DISPLAY_BYTES),
-#undef RTINFENTRY
+#define PROC_REC(name,type) { HERMES_RID_##name, #name, DISPLAY_##type }
+	PROC_REC(CNFPORTTYPE,WORDS),
+	PROC_REC(CNFOWNMACADDR,BYTES),
+	PROC_REC(CNFDESIREDSSID,STRING),
+	PROC_REC(CNFOWNCHANNEL,WORDS),
+	PROC_REC(CNFOWNSSID,STRING),
+	PROC_REC(CNFOWNATIMWINDOW,WORDS),
+	PROC_REC(CNFSYSTEMSCALE,WORDS),
+	PROC_REC(CNFMAXDATALEN,WORDS),
+	PROC_REC(CNFPMENABLED,WORDS),
+	PROC_REC(CNFPMEPS,WORDS),
+	PROC_REC(CNFMULTICASTRECEIVE,WORDS),
+	PROC_REC(CNFMAXSLEEPDURATION,WORDS),
+	PROC_REC(CNFPMHOLDOVERDURATION,WORDS),
+	PROC_REC(CNFOWNNAME,STRING),
+	PROC_REC(CNFOWNDTIMPERIOD,WORDS),
+	PROC_REC(CNFMULTICASTPMBUFFERING,WORDS),
+	PROC_REC(CNFWEPENABLED_AGERE,WORDS),
+	PROC_REC(CNFMANDATORYBSSID_SYMBOL,WORDS),
+	PROC_REC(CNFWEPDEFAULTKEYID,WORDS),
+	PROC_REC(CNFDEFAULTKEY0,BYTES),
+	PROC_REC(CNFDEFAULTKEY1,BYTES),
+	PROC_REC(CNFMWOROBUST_AGERE,WORDS),
+	PROC_REC(CNFDEFAULTKEY2,BYTES),
+	PROC_REC(CNFDEFAULTKEY3,BYTES),
+	PROC_REC(CNFWEPFLAGS_INTERSIL,WORDS),
+	PROC_REC(CNFWEPKEYMAPPINGTABLE,WORDS),
+	PROC_REC(CNFAUTHENTICATION,WORDS),
+	PROC_REC(CNFMAXASSOCSTA,WORDS),
+	PROC_REC(CNFKEYLENGTH_SYMBOL,WORDS),
+	PROC_REC(CNFTXCONTROL,WORDS),
+	PROC_REC(CNFROAMINGMODE,WORDS),
+	PROC_REC(CNFHOSTAUTHENTICATION,WORDS),
+	PROC_REC(CNFRCVCRCERROR,WORDS),
+	PROC_REC(CNFMMLIFE,WORDS),
+	PROC_REC(CNFALTRETRYCOUNT,WORDS),
+	PROC_REC(CNFBEACONINT,WORDS),
+	PROC_REC(CNFAPPCFINFO,WORDS),
+	PROC_REC(CNFSTAPCFINFO,WORDS),
+	PROC_REC(CNFPRIORITYQUSAGE,WORDS),
+	PROC_REC(CNFTIMCTRL,WORDS),
+	PROC_REC(CNFTHIRTY2TALLY,WORDS),
+	PROC_REC(CNFENHSECURITY,WORDS),
+	PROC_REC(CNFGROUPADDRESSES,BYTES),
+	PROC_REC(CNFCREATEIBSS,WORDS),
+	PROC_REC(CNFFRAGMENTATIONTHRESHOLD,WORDS),
+	PROC_REC(CNFRTSTHRESHOLD,WORDS),
+	PROC_REC(CNFTXRATECONTROL,WORDS),
+	PROC_REC(CNFPROMISCUOUSMODE,WORDS),
+	PROC_REC(CNFBASICRATES_SYMBOL,WORDS),
+	PROC_REC(CNFPREAMBLE_SYMBOL,WORDS),
+	PROC_REC(CNFSHORTPREAMBLE,WORDS),
+	PROC_REC(CNFWEPKEYS_AGERE,BYTES),
+	PROC_REC(CNFEXCLUDELONGPREAMBLE,WORDS),
+	PROC_REC(CNFTXKEY_AGERE,WORDS),
+	PROC_REC(CNFAUTHENTICATIONRSPTO,WORDS),
+	PROC_REC(CNFBASICRATES,WORDS),
+	PROC_REC(CNFSUPPORTEDRATES,WORDS),
+	PROC_REC(CNFTICKTIME,WORDS),
+	PROC_REC(CNFSCANREQUEST,WORDS),
+	PROC_REC(CNFJOINREQUEST,WORDS),
+	PROC_REC(CNFAUTHENTICATESTATION,WORDS),
+	PROC_REC(CNFCHANNELINFOREQUEST,WORDS),
+	PROC_REC(MAXLOADTIME,WORDS),
+	PROC_REC(DOWNLOADBUFFER,WORDS),
+	PROC_REC(PRIID,WORDS),
+	PROC_REC(PRISUPRANGE,WORDS),
+	PROC_REC(CFIACTRANGES,WORDS),
+	PROC_REC(NICSERNUM,WORDS),
+	PROC_REC(NICID,WORDS),
+	PROC_REC(MFISUPRANGE,WORDS),
+	PROC_REC(CFISUPRANGE,WORDS),
+	PROC_REC(CHANNELLIST,WORDS),
+	PROC_REC(REGULATORYDOMAINS,WORDS),
+	PROC_REC(TEMPTYPE,WORDS),
+/*  	PROC_REC(CIS,BYTES), */
+	PROC_REC(STAID,WORDS),
+	PROC_REC(CURRENTSSID,STRING),
+	PROC_REC(CURRENTBSSID,BYTES),
+	PROC_REC(COMMSQUALITY,WORDS),
+	PROC_REC(CURRENTTXRATE,WORDS),
+	PROC_REC(CURRENTBEACONINTERVAL,WORDS),
+	PROC_REC(CURRENTSCALETHRESHOLDS,WORDS),
+	PROC_REC(PROTOCOLRSPTIME,WORDS),
+	PROC_REC(SHORTRETRYLIMIT,WORDS),
+	PROC_REC(LONGRETRYLIMIT,WORDS),
+	PROC_REC(MAXTRANSMITLIFETIME,WORDS),
+	PROC_REC(MAXRECEIVELIFETIME,WORDS),
+	PROC_REC(CFPOLLABLE,WORDS),
+	PROC_REC(AUTHENTICATIONALGORITHMS,WORDS),
+	PROC_REC(PRIVACYOPTIONIMPLEMENTED,WORDS),
+	PROC_REC(OWNMACADDR,BYTES),
+	PROC_REC(SCANRESULTSTABLE,WORDS),
+	PROC_REC(PHYTYPE,WORDS),
+	PROC_REC(CURRENTCHANNEL,WORDS),
+	PROC_REC(CURRENTPOWERSTATE,WORDS),
+	PROC_REC(CCAMODE,WORDS),
+	PROC_REC(SUPPORTEDDATARATES,WORDS),
+	PROC_REC(BUILDSEQ,BYTES),
+	PROC_REC(FWID,XSTRING)
+#undef PROC_REC
 };
 #define NUM_RIDS ( sizeof(record_table) / sizeof(record_table[0]) )
 
 static int
-dldwd_proc_get_hermes_recs(char *page, char **start, off_t requested_offset,
+orinoco_proc_get_hermes_recs(char *page, char **start, off_t requested_offset,
 			   int requested_len, int *eof, void *data)
 {
-	dldwd_priv_t *dev = (dldwd_priv_t *)data;
-	hermes_t *hw = &dev->hw;
-	char *buf;
+	struct orinoco_private *priv = (struct orinoco_private *)data;
+	struct net_device *dev = priv->ndev;
+	hermes_t *hw = &priv->hw;
+	char *buf = page;
 	int total = 0, slop = 0;
-	int i;
+	u8 *val8;
+	u16 *val16;
+	int i,j;
 	u16 length;
 	int err;
 
-	/* Hum, in this case hardware register are probably not readable... */
-	if (!dev->hw_ready)
+	if (! netif_device_present(dev))
 		return -ENODEV;
-		
-	buf = page;
 
-	/* print out all the config RIDs */
+	val8 = kmalloc(PROC_LTV_SIZE + 2, GFP_KERNEL);
+	if (! val8)
+		return -ENOMEM;
+	val16 = (u16 *)val8;
+
 	for (i = 0; i < NUM_RIDS; i++) {
 		u16 rid = record_table[i].rid;
-		int minlen = record_table[i].minlen;
-		int maxlen = record_table[i].maxlen;
 		int len;
-		u8 *val8;
-		u16 *val16;
-		int j;
-
-		val8 = kmalloc(maxlen + 2, GFP_KERNEL);
-		if (! val8)
-			return -ENOMEM;
 
-		err = hermes_read_ltv(hw, USER_BAP, rid, maxlen,
+		memset(val8, 0, PROC_LTV_SIZE + 2);
+
+		err = hermes_read_ltv(hw, USER_BAP, rid, PROC_LTV_SIZE,
 				      &length, val8);
 		if (err) {
 			DEBUG(0, "Error %d reading RID 0x%04x\n", err, rid);
 			continue;
 		}
 		val16 = (u16 *)val8;
+		if (length == 0)
+			continue;
 
 		buf += sprintf(buf, "%-15s (0x%04x): length=%d (%d bytes)\tvalue=", record_table[i].name,
 			       rid, length, (length-1)*2);
-		len = min( (int)max(minlen, ((int)length-1)*2), maxlen);
+		len = min(((int)length-1)*2, PROC_LTV_SIZE);
 
 		switch (record_table[i].displaytype) {
 		case DISPLAY_WORDS:
@@ -3589,11 +3745,67 @@
 			val8[len] = '\0';
 			buf += sprintf(buf, "\"%s\"", (char *)&val16[1]);
 			break;
+
+		case DISPLAY_XSTRING:
+			buf += sprintf(buf, "'%s'", (char *)val8);
 		}
 
 		buf += sprintf(buf, "\n");
 
-		kfree(val8);
+		if (shift_buffer(page, requested_offset, requested_len,
+				 &total, &slop, &buf))
+			break;
+
+		if ( (buf - page) > PROC_SAFE_SIZE )
+			break;
+	}
+
+	kfree(val8);
+
+	return calc_start_len(page, start, requested_offset, requested_len,
+			      total, buf);
+}
+
+#ifdef HERMES_DEBUG_BUFFER
+static int
+orinoco_proc_get_hermes_buf(char *page, char **start, off_t requested_offset,
+			    int requested_len, int *eof, void *data)
+{
+	struct orinoco_private *priv = (struct orinoco_private *)data;
+	hermes_t *hw = &priv->hw;
+	char *buf = page;
+	int total = 0, slop = 0;
+	int i;
+
+	for (i = 0; i < min_t(int,hw->dbufp, HERMES_DEBUG_BUFSIZE); i++) {
+		memcpy(buf, &hw->dbuf[i], sizeof(hw->dbuf[i]));
+		buf += sizeof(hw->dbuf[i]);
+
+		if (shift_buffer(page, requested_offset, requested_len,
+				 &total, &slop, &buf))
+			break;
+
+		if ( (buf - page) > PROC_SAFE_SIZE )
+			break;
+	}
+
+	return calc_start_len(page, start, requested_offset, requested_len,
+			      total, buf);
+}
+
+static int
+orinoco_proc_get_hermes_prof(char *page, char **start, off_t requested_offset,
+			    int requested_len, int *eof, void *data)
+{
+	struct orinoco_private *priv = (struct orinoco_private *)data;
+	hermes_t *hw = &priv->hw;
+	char *buf = page;
+	int total = 0, slop = 0;
+	int i;
+
+	for (i = 0; i < (HERMES_BAP_BUSY_TIMEOUT+1); i++) {
+		memcpy(buf, &hw->profile[i], sizeof(hw->profile[i]));
+		buf += sizeof(hw->profile[i]);
 
 		if (shift_buffer(page, requested_offset, requested_len,
 				 &total, &slop, &buf))
@@ -3606,161 +3818,165 @@
 	return calc_start_len(page, start, requested_offset, requested_len,
 			      total, buf);
 }
+#endif /* HERMES_DEBUG_BUFFER */
 
 /* initialise the /proc subsystem for the hermes driver, creating the
  * separate entries */
 static int
-dldwd_proc_init(void)
+orinoco_proc_init(void)
 {
 	int err = 0;
 
-	TRACE_ENTER("dldwd");
+	TRACE_ENTER("orinoco");
 
 	/* create the directory for it to sit in */
 	dir_base = create_proc_entry("hermes", S_IFDIR, &proc_root);
 	if (dir_base == NULL) {
 		printk(KERN_ERR "Unable to initialise /proc/hermes.\n");
-		dldwd_proc_cleanup();
+		orinoco_proc_cleanup();
 		err = -ENOMEM;
 	}
 
-	TRACE_EXIT("dldwd");
+	TRACE_EXIT("orinoco");
 
 	return err;
 }
 
 int
-dldwd_proc_dev_init(dldwd_priv_t *dev)
+orinoco_proc_dev_init(struct orinoco_private *priv)
 {
-	struct net_device *ndev = &dev->ndev;
+	struct net_device *dev = priv->ndev;
+	struct proc_dir_entry *e;
+
+	priv->dir_dev = NULL;
 
-	dev->dir_dev = NULL;
 	/* create the directory for it to sit in */
-	dev->dir_dev = create_proc_entry(ndev->name, S_IFDIR | S_IRUGO | S_IXUGO,
-					 dir_base);
-	if (dev->dir_dev == NULL) {
-		printk(KERN_ERR "Unable to initialise /proc/hermes/%s.\n",  ndev->name);
+	priv->dir_dev = create_proc_entry(dev->name, S_IFDIR | S_IRUGO | S_IXUGO,
+					  dir_base);
+	if (! priv->dir_dev) {
+		printk(KERN_ERR "Unable to initialize /proc/hermes/%s\n",  dev->name);
+		goto fail;
+	}
+
+	e = create_proc_read_entry("recs", S_IFREG | S_IRUGO,
+			       priv->dir_dev, orinoco_proc_get_hermes_recs, priv);
+	if (! e) {
+		printk(KERN_ERR "Unable to initialize /proc/hermes/%s/recs\n",  dev->name);
 		goto fail;
 	}
 
-	dev->dir_regs = NULL;
-	dev->dir_regs = create_proc_read_entry("regs", S_IFREG | S_IRUGO,
-					       dev->dir_dev, dldwd_proc_get_hermes_regs, dev);
-	if (dev->dir_regs == NULL) {
-		printk(KERN_ERR "Unable to initialise /proc/hermes/%s/regs.\n",  ndev->name);
+#ifdef HERMES_DEBUG_BUFFER
+	e = create_proc_read_entry("buf", S_IFREG | S_IRUGO,
+					       priv->dir_dev, orinoco_proc_get_hermes_buf, priv);
+	if (! e) {
+		printk(KERN_ERR "Unable to intialize /proc/hermes/%s/buf\n", dev->name);
 		goto fail;
 	}
 
-	dev->dir_recs = NULL;
-	dev->dir_recs = create_proc_read_entry("recs", S_IFREG | S_IRUGO,
-					       dev->dir_dev, dldwd_proc_get_hermes_recs, dev);
-	if (dev->dir_recs == NULL) {
-		printk(KERN_ERR "Unable to initialise /proc/hermes/%s/recs.\n",  ndev->name);
+	e = create_proc_read_entry("prof", S_IFREG | S_IRUGO,
+					       priv->dir_dev, orinoco_proc_get_hermes_prof, priv);
+	if (! e) {
+		printk(KERN_ERR "Unable to intialize /proc/hermes/%s/prof\n", dev->name);
 		goto fail;
 	}
+#endif /* HERMES_DEBUG_BUFFER */
 
 	return 0;
  fail:
-	dldwd_proc_dev_cleanup(dev);
+	orinoco_proc_dev_cleanup(priv);
 	return -ENOMEM;
 }
 
 void
-dldwd_proc_dev_cleanup(dldwd_priv_t *priv)
+orinoco_proc_dev_cleanup(struct orinoco_private *priv)
 {
-	struct net_device *ndev = &priv->ndev;
+	struct net_device *dev = priv->ndev;
+
+	TRACE_ENTER(priv->ndev->name);
 
-	if (priv->dir_regs) {
-		remove_proc_entry("regs", priv->dir_dev);
-		priv->dir_regs = NULL;
-	}		
-	if (priv->dir_recs) {
-		remove_proc_entry("recs", priv->dir_dev);
-		priv->dir_recs = NULL;
-	}		
 	if (priv->dir_dev) {
-		remove_proc_entry(ndev->name, dir_base);
+		remove_proc_entry("prof", priv->dir_dev);
+		remove_proc_entry("buf", priv->dir_dev);
+		remove_proc_entry("recs", priv->dir_dev);
+		remove_proc_entry(dev->name, dir_base);
 		priv->dir_dev = NULL;
 	}
+
+	TRACE_EXIT(priv->ndev->name);
 }
 
 static void
-dldwd_proc_cleanup(void)
+orinoco_proc_cleanup(void)
 {
-	TRACE_ENTER("dldwd");
+	TRACE_ENTER("orinoco");
 
 	if (dir_base) {
 		remove_proc_entry("hermes", &proc_root);
 		dir_base = NULL;
 	}
 	
-	TRACE_EXIT("dldwd");
+	TRACE_EXIT("orinoco");
 }
 
-int
-dldwd_setup(dldwd_priv_t* priv)
+struct net_device *alloc_orinocodev(int sizeof_card)
 {
-	struct net_device *dev = &priv->ndev;;
+	struct net_device *dev;
+	struct orinoco_private *priv;
 
-	spin_lock_init(&priv->lock);
-
-	/* Set up the net_device */
-	ether_setup(dev);
-	dev->priv = priv;
-
-	/* Setup up default routines */
-	priv->card_reset_handler = NULL;	/* Caller may override */
-	dev->init = dldwd_init;
-	dev->open = NULL;		/* Caller *must* override */
-	dev->stop = NULL;
-	dev->hard_start_xmit = dldwd_xmit;
-	dev->tx_timeout = dldwd_tx_timeout;
-	dev->watchdog_timeo = HZ; /* 4 second timeout */
+	TRACE_ENTER("orinoco");
+	dev = alloc_etherdev(sizeof(struct orinoco_private) + sizeof_card);
+	priv = (struct orinoco_private *)dev->priv;
+	priv->ndev = dev;
+	if (sizeof_card)
+		priv->card = (void *)((unsigned long)dev->priv + sizeof(struct orinoco_private));
+	else
+		priv->card = NULL;
 
-	dev->get_stats = dldwd_get_stats;
-	dev->get_wireless_stats = dldwd_get_wireless_stats;
+	/* Setup / override net_device fields */
+	dev->init = orinoco_init;
+	dev->hard_start_xmit = orinoco_xmit;
+	dev->tx_timeout = orinoco_tx_timeout;
+	dev->watchdog_timeo = HZ; /* 1 second timeout */
+	dev->get_stats = orinoco_get_stats;
+	dev->get_wireless_stats = orinoco_get_wireless_stats;
+	dev->do_ioctl = orinoco_ioctl;
+	dev->change_mtu = orinoco_change_mtu;
+	dev->set_multicast_list = orinoco_set_multicast_list;
 
-	dev->do_ioctl = dldwd_ioctl;
+	dev->open = NULL;		/* Caller *must* override  these */
+	dev->stop = NULL;
 
-	dev->change_mtu = dldwd_change_mtu;
-	dev->set_multicast_list = dldwd_set_multicast_list;
+	/* Setup the private structure */
 
-	netif_stop_queue(dev);
+	spin_lock_init(&priv->lock);
+	priv->hard_reset = NULL;	/* Caller may override */
+	
+	TRACE_EXIT("orinoco");
+	return dev;
 
-	return 0;
 }
 
-#ifdef ORINOCO_DEBUG
-EXPORT_SYMBOL(dldwd_debug);
-#endif
-EXPORT_SYMBOL(dldwd_init);
-EXPORT_SYMBOL(dldwd_xmit);
-EXPORT_SYMBOL(dldwd_tx_timeout);
-EXPORT_SYMBOL(dldwd_ioctl);
-EXPORT_SYMBOL(dldwd_change_mtu);
-EXPORT_SYMBOL(dldwd_set_multicast_list);
-EXPORT_SYMBOL(dldwd_shutdown);
-EXPORT_SYMBOL(dldwd_reset);
-EXPORT_SYMBOL(dldwd_setup);
-EXPORT_SYMBOL(dldwd_proc_dev_init);
-EXPORT_SYMBOL(dldwd_proc_dev_cleanup);
-EXPORT_SYMBOL(dldwd_interrupt);
-
-static int __init init_dldwd(void)
-{
-	int err;
+/********************************************************************/
+/* module bookkeeping                                               */
+/********************************************************************/
 
-	err = dldwd_proc_init();
+EXPORT_SYMBOL(alloc_orinocodev);
+EXPORT_SYMBOL(orinoco_shutdown);
+EXPORT_SYMBOL(orinoco_reset);
+EXPORT_SYMBOL(orinoco_proc_dev_init);
+EXPORT_SYMBOL(orinoco_proc_dev_cleanup);
+EXPORT_SYMBOL(orinoco_interrupt);
 
+static int __init init_orinoco(void)
+{
 	printk(KERN_DEBUG "%s\n", version);
-
-	return 0;
+	return orinoco_proc_init();
 }
 
-static void __exit exit_dldwd(void)
+static void __exit exit_orinoco(void)
 {
-	dldwd_proc_cleanup();
+	orinoco_proc_cleanup();
 }
 
-module_init(init_dldwd);
-module_exit(exit_dldwd);
+module_init(init_orinoco);
+module_exit(exit_orinoco);
diff -Nru a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h
--- a/drivers/net/wireless/orinoco.h	Tue Apr 30 17:10:25 2002
+++ b/drivers/net/wireless/orinoco.h	Tue Apr 30 17:10:25 2002
@@ -8,110 +8,95 @@
 #define _ORINOCO_H
 
 /* To enable debug messages */
-/*  #define ORINOCO_DEBUG		3 */
+//#define ORINOCO_DEBUG		3
 
 #if (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10)
-#error "orinoco_cs requires Wireless extensions v10 or later."
+#error "orinoco driver requires Wireless extensions v10 or later."
 #endif /* (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) */
 #define WIRELESS_SPY		// enable iwspy support
 
+#define ORINOCO_MAX_KEY_SIZE	14
+#define ORINOCO_MAX_KEYS	4
 
-#define DLDWD_MIN_MTU		256
-#define DLDWD_MAX_MTU		(HERMES_FRAME_LEN_MAX - ENCAPS_OVERHEAD)
+typedef struct orinoco_key {
+	u16 len;	/* always store little-endian */
+	char data[ORINOCO_MAX_KEY_SIZE];
+} __attribute__ ((packed)) orinoco_key_t;
 
-#define LTV_BUF_SIZE		128
-#define USER_BAP		0
-#define IRQ_BAP			1
-#define DLDWD_MACPORT		0
-#define IRQ_LOOP_MAX		10
-#define TX_NICBUF_SIZE		2048
-#define TX_NICBUF_SIZE_BUG	1585		/* Bug in Symbol firmware */
-#define MAX_KEYS		4
-#define MAX_KEY_SIZE		14
-#define LARGE_KEY_SIZE		13
-#define SMALL_KEY_SIZE		5
-#define MAX_FRAME_SIZE		2304
-
-typedef struct dldwd_key {
-	uint16_t len;	/* always store little-endian */
-	char data[MAX_KEY_SIZE];
-} __attribute__ ((packed)) dldwd_key_t;
-
-typedef dldwd_key_t dldwd_keys_t[MAX_KEYS];
+typedef orinoco_key_t orinoco_keys_t[ORINOCO_MAX_KEYS];
 
 /*====================================================================*/
 
-
-typedef struct dldwd_priv {
-	void* card;	/* Pointer to card dependant structure */
+struct orinoco_private {
+	void *card;	/* Pointer to card dependant structure */
 	/* card dependant extra reset code (i.e. bus/interface specific */
-	int (*card_reset_handler)(struct dldwd_priv *);
+	int (*hard_reset)(struct orinoco_private *);
 
 	spinlock_t lock;
 	long state;
-#define DLDWD_STATE_INIRQ 0
-#define DLDWD_STATE_DOIRQ 1
-	int hw_ready;	/* HW may be suspended by platform */
+#define ORINOCO_STATE_INIRQ 0
+#define ORINOCO_STATE_DOIRQ 1
 
 	/* Net device stuff */
-	struct net_device ndev;
+	struct net_device *ndev;
 	struct net_device_stats stats;
 	struct iw_statistics wstats;
 
-
 	/* Hardware control variables */
 	hermes_t hw;
-	uint16_t txfid;
+	u16 txfid;
 
 	/* Capabilities of the hardware/firmware */
 	int firmware_type;
-#define FIRMWARE_TYPE_LUCENT 1
+#define FIRMWARE_TYPE_AGERE 1
 #define FIRMWARE_TYPE_INTERSIL 2
 #define FIRMWARE_TYPE_SYMBOL 3
-	int has_ibss, has_port3, prefer_port3, has_ibss_any, ibss_port;
+	int has_ibss, has_port3, has_ibss_any, ibss_port;
 	int has_wep, has_big_wep;
 	int has_mwo;
 	int has_pm;
 	int has_preamble;
-	int need_card_reset, broken_reset, broken_allocate;
-	uint16_t channel_mask;
-
-	/* Current configuration */
-	uint32_t iw_mode;
-	int port_type, allow_ibss;
-	uint16_t wep_on, wep_restrict, tx_key;
-	dldwd_keys_t keys;
+	int has_sensitivity;
+	int nicbuf_size;
+	int broken_cor_reset;
+	u16 channel_mask;
+
+	/* Configuration paramaters */
+	u32 iw_mode;
+	int prefer_port3;
+	u16 wep_on, wep_restrict, tx_key;
+	orinoco_keys_t keys;
+	int bitratemode;
  	char nick[IW_ESSID_MAX_SIZE+1];
 	char desired_essid[IW_ESSID_MAX_SIZE+1];
-	uint16_t frag_thresh, mwo_robust;
-	uint16_t channel;
-	uint16_t ap_density, rts_thresh;
-	uint16_t tx_rate_ctrl;
-	uint16_t pm_on, pm_mcast, pm_period, pm_timeout;
-	uint16_t preamble;
-
-	int promiscuous, allmulti, mc_count;
-
+	u16 frag_thresh, mwo_robust;
+	u16 channel;
+	u16 ap_density, rts_thresh;
+	u16 pm_on, pm_mcast, pm_period, pm_timeout;
+	u16 preamble;
 #ifdef WIRELESS_SPY
 	int			spy_number;
 	u_char			spy_address[IW_MAX_SPY][ETH_ALEN];
 	struct iw_quality	spy_stat[IW_MAX_SPY];
 #endif
 
+	/* Configuration dependent variables */
+	int port_type, allow_ibss;
+	int promiscuous, mc_count;
+
+
 	/* /proc based debugging stuff */
 	struct proc_dir_entry *dir_dev;
-	struct proc_dir_entry *dir_regs;
-	struct proc_dir_entry *dir_recs;
-} dldwd_priv_t;
+};
 
 /*====================================================================*/
 
-extern struct list_head dldwd_instances;
+extern struct list_head orinoco_instances;
 
 #ifdef ORINOCO_DEBUG
-extern int dldwd_debug;
-#define DEBUG(n, args...) do { if (dldwd_debug>(n)) printk(KERN_DEBUG args); } while(0)
-#define DEBUGMORE(n, args...) do { if (dldwd_debug>(n)) printk(args); } while (0)
+extern int orinoco_debug;
+#define DEBUG(n, args...) do { if (orinoco_debug>(n)) printk(KERN_DEBUG args); } while(0)
+#define DEBUGMORE(n, args...) do { if (orinoco_debug>(n)) printk(args); } while (0)
 #else
 #define DEBUG(n, args...) do { } while (0)
 #define DEBUGMORE(n, args...) do { } while (0)
@@ -122,21 +107,12 @@
 
 #define RUP_EVEN(a) ( (a) % 2 ? (a) + 1 : (a) )
 
-/* struct net_device methods */
-extern int dldwd_init(struct net_device *dev);
-extern int dldwd_xmit(struct sk_buff *skb, struct net_device *dev);
-extern void dldwd_tx_timeout(struct net_device *dev);
-
-extern int dldwd_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-extern int dldwd_change_mtu(struct net_device *dev, int new_mtu);
-extern void dldwd_set_multicast_list(struct net_device *dev);
-
 /* utility routines */
-extern void dldwd_shutdown(dldwd_priv_t *dev);
-extern int dldwd_reset(dldwd_priv_t *dev);
-extern int dldwd_setup(dldwd_priv_t* priv);
-extern int dldwd_proc_dev_init(dldwd_priv_t *dev);
-extern void dldwd_proc_dev_cleanup(dldwd_priv_t *priv);
-extern void dldwd_interrupt(int irq, void * dev_id, struct pt_regs *regs);
+struct net_device *alloc_orinocodev(int sizeof_card);
+extern void orinoco_shutdown(struct orinoco_private *dev);
+extern int orinoco_reset(struct orinoco_private *dev);
+extern int orinoco_proc_dev_init(struct orinoco_private *dev);
+extern void orinoco_proc_dev_cleanup(struct orinoco_private *priv);
+extern void orinoco_interrupt(int irq, void * dev_id, struct pt_regs *regs);
 
-#endif
+#endif /* _ORINOCO_H */
diff -Nru a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c
--- a/drivers/net/wireless/orinoco_cs.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/net/wireless/orinoco_cs.c	Tue Apr 30 17:10:25 2002
@@ -1,4 +1,4 @@
-/* orinoco_cs.c 0.08a	- (formerly known as dldwd_cs.c)
+/* orinoco_cs.c 0.11a	- (formerly known as dldwd_cs.c)
  *
  * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such
  * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/
@@ -11,6 +11,9 @@
  */
 
 #include <linux/config.h>
+#ifdef  __IN_PCMCIA_PACKAGE__
+#include <pcmcia/k_compat.h>
+#endif /* __IN_PCMCIA_PACKAGE__ */
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -44,11 +47,13 @@
 
 /*====================================================================*/
 
-static char version[] __initdata = "orinoco_cs.c 0.08a (David Gibson <hermes@gibson.dropbear.id.au> and others)";
+static char version[] __initdata = "orinoco_cs.c 0.11a (David Gibson <hermes@gibson.dropbear.id.au> and others)";
 
 MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>");
 MODULE_DESCRIPTION("Driver for PCMCIA Lucent Orinoco, Prism II based and similar wireless cards");
+#ifdef MODULE_LICENSE
 MODULE_LICENSE("Dual MPL/GPL");
+#endif
 
 /* Parameters that can be set with 'insmod' */
 
@@ -58,7 +63,7 @@
 /* Newer, simpler way of listing specific interrupts */
 static int irq_list[4] = { -1 };
 /* Do a Pcmcia soft reset (may help some cards) */
-static int reset_cor = 0;
+static int reset_cor = -1;
 /* Some D-Link cards have buggy CIS. They do work at 5v properly, but
  * don't have any CIS entry for it. This workaround it... */
 static int ignore_cis_vcc; /* = 0 */
@@ -68,40 +73,34 @@
 MODULE_PARM(reset_cor, "i");
 MODULE_PARM(ignore_cis_vcc, "i");
 
-
 /* Pcmcia specific structure */
-typedef struct dldwd_card {
+struct orinoco_pccard {
 	dev_link_t link;
 	dev_node_t node;
-	int instance;
-
-	/* Common structure (fully included), see orinoco.h */
-	struct dldwd_priv  priv;
-} dldwd_card_t;
+};
 
 /*
  * Function prototypes
  */
 
 /* struct net_device methods */
-static int dldwd_cs_open(struct net_device *dev);
-static int dldwd_cs_stop(struct net_device *dev);
+static int orinoco_cs_open(struct net_device *dev);
+static int orinoco_cs_stop(struct net_device *dev);
 
 /* PCMCIA gumpf */
-static void dldwd_cs_config(dev_link_t * link);
-static void dldwd_cs_release(u_long arg);
-static int dldwd_cs_event(event_t event, int priority,
+static void orinoco_cs_config(dev_link_t * link);
+static void orinoco_cs_release(u_long arg);
+static int orinoco_cs_event(event_t event, int priority,
 		       event_callback_args_t * args);
 
-static dev_link_t *dldwd_cs_attach(void);
-static void dldwd_cs_detach(dev_link_t *);
+static dev_link_t *orinoco_cs_attach(void);
+static void orinoco_cs_detach(dev_link_t *);
 
 /*
    The dev_info variable is the "key" that is used to match up this
    device driver with appropriate cards, through the card configuration
    database.
 */
-
 static dev_info_t dev_info = "orinoco_cs";
 
 /*
@@ -115,7 +114,6 @@
 */
 
 static dev_link_t *dev_list; /* = NULL */
-static int num_instances; /* = 0 */
 
 /*====================================================================*/
 
@@ -127,48 +125,48 @@
 }
 
 static int
-dldwd_cs_open(struct net_device *dev)
+orinoco_cs_open(struct net_device *dev)
 {
-	dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
-	dldwd_card_t* card = (dldwd_card_t *)priv->card;
+	struct orinoco_private *priv = (struct orinoco_private *)dev->priv;
+	struct orinoco_pccard* card = (struct orinoco_pccard *)priv->card;
 	dev_link_t *link = &card->link;
 	int err;
 	
-	TRACE_ENTER(priv->ndev.name);
+	TRACE_ENTER(dev->name);
 
 	link->open++;
 	netif_device_attach(dev);
 	
-	err = dldwd_reset(priv);
+	err = orinoco_reset(priv);
 	if (err)
-		dldwd_cs_stop(dev);
+		orinoco_cs_stop(dev);
 	else
 		netif_start_queue(dev);
 
-	TRACE_EXIT(priv->ndev.name);
+	TRACE_EXIT(dev->name);
 
 	return err;
 }
 
 static int
-dldwd_cs_stop(struct net_device *dev)
+orinoco_cs_stop(struct net_device *dev)
 {
-	dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
-	dldwd_card_t* card = (dldwd_card_t *)priv->card;
+	struct orinoco_private *priv = (struct orinoco_private *)dev->priv;
+	struct orinoco_pccard* card = (struct orinoco_pccard *)priv->card;
 	dev_link_t *link = &card->link;
 
-	TRACE_ENTER(priv->ndev.name);
+	TRACE_ENTER(dev->name);
 
 	netif_stop_queue(dev);
 
-	dldwd_shutdown(priv);
+	orinoco_shutdown(priv);
 	
 	link->open--;
 
 	if (link->state & DEV_STALE_CONFIG)
 		mod_timer(&link->release, jiffies + HZ/20);
 	
-	TRACE_EXIT(priv->ndev.name);
+	TRACE_EXIT(dev->name);
 	
 	return 0;
 }
@@ -179,18 +177,18 @@
  * In fact, this seem necessary for Spectrum cards...
  */
 static int
-dldwd_cs_cor_reset(dldwd_priv_t *priv)
+orinoco_cs_cor_reset(struct orinoco_private *priv)
 {
-	dldwd_card_t* card = (dldwd_card_t *)priv->card;
+	struct orinoco_pccard* card = (struct orinoco_pccard *)priv->card;
 	dev_link_t *link = &card->link;
 	conf_reg_t reg;
 	u_int default_cor; 
 
-	TRACE_ENTER(priv->ndev.name);
+	TRACE_ENTER(priv->ndev->name);
 
 	/* Doing it if hardware is gone is guaranteed crash */
-	if(!priv->hw_ready)
-		return(0);
+	if(! (link->state & DEV_CONFIG) )
+		return -ENODEV;
 
 	/* Save original COR value */
 	reg.Function = 0;
@@ -200,7 +198,7 @@
 	CardServices(AccessConfigurationRegister, link->handle, &reg);
 	default_cor = reg.Value;
 
-	DEBUG(2, "dldwd : dldwd_cs_cor_reset() : cor=0x%X\n", default_cor);
+	DEBUG(2, "orinoco : orinoco_cs_cor_reset() : cor=0x%X\n", default_cor);
 
 	/* Soft-Reset card */
 	reg.Action = CS_WRITE;
@@ -209,18 +207,57 @@
 	CardServices(AccessConfigurationRegister, link->handle, &reg);
 
 	/* Wait until the card has acknowledged our reset */
+	/* FIXME: mdelay() is deprecated -dgibson */
+	mdelay(1);
+
+#if 0 /* This seems to help on Symbol cards, but we're not sure why,
+       and we don't know what it will do to other cards */
+	reg.Action = CS_READ;
+	reg.Offset = CISREG_CCSR;
+	CardServices(AccessConfigurationRegister, link->handle, &reg);
+
+	/* Write 7 (RUN) to CCSR, but preserve the original bit 4 */
+	reg.Action = CS_WRITE;
+	reg.Offset = CISREG_CCSR;
+	reg.Value = 7 | (reg.Value & 0x10);
+	CardServices(AccessConfigurationRegister, link->handle, &reg);
 	mdelay(1);
+#endif
 
 	/* Restore original COR configuration index */
+	reg.Action = CS_WRITE;
+	reg.Offset = CISREG_COR;
 	reg.Value = (default_cor & ~COR_SOFT_RESET);
 	CardServices(AccessConfigurationRegister, link->handle, &reg);
 
 	/* Wait until the card has finished restarting */
+	/* FIXME: mdelay() is deprecated -dgibson */
 	mdelay(1);
 
-	TRACE_EXIT(priv->ndev.name);
+	TRACE_EXIT(priv->ndev->name);
 
-	return(0);
+	return 0;
+}
+
+static int
+orinoco_cs_hard_reset(struct orinoco_private *priv)
+{
+	if (! priv->broken_cor_reset)
+		return orinoco_cs_cor_reset(priv);
+	else
+		return 0;
+
+#if 0 /* We'd like to use ResetCard, but we can't for the moment - it sleeps */
+	/* Not sure what the second parameter is supposed to be - the 
+	   PCMCIA code doesn't actually use it */
+	if (in_interrupt()) {
+		printk("Not resetting card, in_interrupt() is true\n");
+		return 0;
+	} else {
+		printk("Doing ResetCard\n");
+		return CardServices(ResetCard, link->handle, NULL);
+	}
+#endif
 }
 
 /* Remove zombie instances (card removed, detach pending) */
@@ -228,17 +265,17 @@
 flush_stale_links(void)
 {
 	dev_link_t *link, *next;
-	TRACE_ENTER("dldwd");
+	TRACE_ENTER("orinoco");
 	for (link = dev_list; link; link = next) {
 		next = link->next;
 		if (link->state & DEV_STALE_LINK)
-			dldwd_cs_detach(link);
+			orinoco_cs_detach(link);
 	}
-	TRACE_EXIT("dldwd");
+	TRACE_EXIT("orinoco");
 }
 
 /*======================================================================
-  dldwd_cs_attach() creates an "instance" of the driver, allocating
+  orinoco_cs_attach() creates an "instance" of the driver, allocating
   local data structures for one device.  The device is registered
   with Card Services.
   
@@ -248,37 +285,35 @@
   ======================================================================*/
 
 static dev_link_t *
-dldwd_cs_attach(void)
+orinoco_cs_attach(void)
 {
-	dldwd_card_t *card;
-	dldwd_priv_t *priv;
+	struct net_device *dev;
+	struct orinoco_private *priv;
+	struct orinoco_pccard *card;
 	dev_link_t *link;
-	struct net_device *ndev;
 	client_reg_t client_reg;
 	int ret, i;
 
-	TRACE_ENTER("dldwd");
+	TRACE_ENTER("orinoco");
 	/* A bit of cleanup */
 	flush_stale_links();
 
-	/* Allocate space for private device-specific data */
-	card = kmalloc(sizeof(*card), GFP_KERNEL);
-	if (! card) {
-		link = NULL;
-		goto out;
-	}
-	memset(card, 0, sizeof(*card));
+	dev = alloc_orinocodev(sizeof(*card));
+	if (! dev)
+		return NULL;
+	priv = dev->priv;
+	card = priv->card;
+	/* Overrides */
+	dev->open = orinoco_cs_open;
+	dev->stop = orinoco_cs_stop;
+	priv->hard_reset = orinoco_cs_hard_reset;
 
-	/* Link both structure together */
-	priv = &(card->priv);
-	priv->card = card;
-	card->instance = num_instances++; /* FIXME: Racy? */
+	/* Link both structures together */
 	link = &card->link;
-	ndev = &priv->ndev;
 	link->priv = priv;
 
 	/* Initialize the dev_link_t structure */
-	link->release.function = &dldwd_cs_release;
+	link->release.function = &orinoco_cs_release;
 	link->release.data = (u_long) link;
 
 	/* Interrupt setup */
@@ -301,17 +336,6 @@
 	link->conf.Attributes = 0;
 	link->conf.IntType = INT_MEMORY_AND_IO;
 
-	/* Setup the common part */
-	if(dldwd_setup(priv) < 0) {
-		kfree(card);
-		return NULL;
-	}
-
-	/* Overrides */
-	ndev->open = dldwd_cs_open;
-	ndev->stop = dldwd_cs_stop;
-	priv->card_reset_handler = dldwd_cs_cor_reset;
-
 	/* Register with Card Services */
 	link->next = dev_list;
 	dev_list = link;
@@ -321,21 +345,21 @@
 	    CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
 	    CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
 	    CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-	client_reg.event_handler = &dldwd_cs_event;
+	client_reg.event_handler = &orinoco_cs_event;
 	client_reg.Version = 0x0210;
 	client_reg.event_callback_args.client_data = link;
 	ret = CardServices(RegisterClient, &link->handle, &client_reg);
 	if (ret != CS_SUCCESS) {
 		cs_error(link->handle, RegisterClient, ret);
-		dldwd_cs_detach(link);
+		orinoco_cs_detach(link);
 		link = NULL;
 		goto out;
 	}
 
  out:
-	TRACE_EXIT("dldwd");
+	TRACE_EXIT("orinoco");
 	return link;
-}				/* dldwd_cs_attach */
+}				/* orinoco_cs_attach */
 
 /*======================================================================
   This deletes a driver "instance".  The device is de-registered
@@ -345,12 +369,12 @@
   ======================================================================*/
 
 static void
-dldwd_cs_detach(dev_link_t * link)
+orinoco_cs_detach(dev_link_t * link)
 {
 	dev_link_t **linkp;
-	dldwd_priv_t *priv = link->priv;
+	struct orinoco_private *priv = link->priv;
 
-	TRACE_ENTER("dldwd");
+	TRACE_ENTER("orinoco");
 
 	/* Locate device structure */
 	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
@@ -383,19 +407,17 @@
 	DEBUG(0, "orinoco_cs: detach: link=%p link->dev=%p\n", link, link->dev);
 	if (link->dev) {
 		DEBUG(0, "orinoco_cs: About to unregister net device %p\n",
-		      &priv->ndev);
-		unregister_netdev(&priv->ndev);
+		      priv->ndev);
+		unregister_netdev(priv->ndev);
 	}
 	kfree(priv->card);
 
-	num_instances--; /* FIXME: Racy? */
-
  out:
-	TRACE_EXIT("dldwd");
-}				/* dldwd_cs_detach */
+	TRACE_EXIT("orinoco");
+}				/* orinoco_cs_detach */
 
 /*======================================================================
-  dldwd_cs_config() is scheduled to run after a CARD_INSERTION event
+  orinoco_cs_config() is scheduled to run after a CARD_INSERTION event
   is received, to configure the PCMCIA socket, and to make the
   device available to the system.
   ======================================================================*/
@@ -407,13 +429,13 @@
 if (CardServices(fn, args) != 0) goto next_entry
 
 static void
-dldwd_cs_config(dev_link_t * link)
+orinoco_cs_config(dev_link_t * link)
 {
 	client_handle_t handle = link->handle;
-	dldwd_priv_t *priv = link->priv;
-	dldwd_card_t *card = (dldwd_card_t *)priv->card;
+	struct orinoco_private *priv = link->priv;
+	struct orinoco_pccard *card = (struct orinoco_pccard *)priv->card;
 	hermes_t *hw = &priv->hw;
-	struct net_device *ndev = &priv->ndev;
+	struct net_device *ndev = priv->ndev;
 	tuple_t tuple;
 	cisparse_t parse;
 	int last_fn, last_ret;
@@ -422,7 +444,7 @@
 	cistpl_cftable_entry_t dflt = { 0 };
 	cisinfo_t info;
 
-	TRACE_ENTER("dldwd");
+	TRACE_ENTER("orinoco");
 
 	CS_CHECK(ValidateCIS, handle, &info);
 
@@ -448,7 +470,7 @@
 	CS_CHECK(GetConfigurationInfo, handle, &conf);
 	link->conf.Vcc = conf.Vcc;
 
-	DEBUG(0, "dldwd_cs_config: ConfigBase = 0x%x link->conf.Vcc = %d\n", 
+	DEBUG(0, "orinoco_cs_config: ConfigBase = 0x%x link->conf.Vcc = %d\n", 
 	      link->conf.ConfigBase, link->conf.Vcc);
 
 	/*
@@ -470,7 +492,7 @@
 		CFG_CHECK(GetTupleData, handle, &tuple);
 		CFG_CHECK(ParseTuple, handle, &tuple, &parse);
 
-		DEBUG(0, "dldwd_cs_config: index = 0x%x, flags = 0x%x\n",
+		DEBUG(0, "orinoco_cs_config: index = 0x%x, flags = 0x%x\n",
 		      cfg->index, cfg->flags);
 
 		if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
@@ -488,16 +510,14 @@
 		/* Use power settings for Vcc and Vpp if present */
 		/*  Note that the CIS values need to be rescaled */
 		if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
-			if (conf.Vcc !=
-			    cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
-				DEBUG(2, "dldwd_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n",  conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
-				if(!ignore_cis_vcc)
+			if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
+				DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n",  conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
+				if (!ignore_cis_vcc)
 					goto next_entry;
 			}
 		} else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
-			if (conf.Vcc !=
-			    dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) {
-				DEBUG(2, "dldwd_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n",  conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000);
+			if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) {
+				DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n",  conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000);
 				if(!ignore_cis_vcc)
 					goto next_entry;
 			}
@@ -510,7 +530,7 @@
 			link->conf.Vpp1 = link->conf.Vpp2 =
 			    dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
 		
-		DEBUG(0, "dldwd_cs_config: We seem to have configured Vcc and Vpp\n");
+		DEBUG(0, "orinoco_cs_config: We seem to have configured Vcc and Vpp\n");
 
 		/* Do we need to allocate an interrupt? */
 		if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
@@ -551,7 +571,12 @@
 	next_entry:
 		if (link->io.NumPorts1)
 			CardServices(ReleaseIO, link->handle, &link->io);
-		CS_CHECK(GetNextTuple, handle, &tuple);
+		last_ret = CardServices(GetNextTuple, handle, &tuple);
+		if (last_ret  == CS_NO_MORE_ITEMS) {
+			printk(KERN_ERR "GetNextTuple().  No matching CIS configuration, "
+			       "maybe you need the ignore_cis_vcc=1 parameter.\n");
+			goto cs_failed;
+		}
 	}
 
 	/*
@@ -570,7 +595,7 @@
 			for (i=0; i<4; i++)
 				link->irq.IRQInfo2 |= 1 << irq_list[i];
 		
-  		link->irq.Handler = dldwd_interrupt; 
+  		link->irq.Handler = orinoco_interrupt; 
   		link->irq.Instance = priv; 
 		
 		CS_CHECK(RequestIRQ, link->handle, &link->irq);
@@ -579,7 +604,8 @@
 	/* We initialize the hermes structure before completing PCMCIA
 	   configuration just in case the interrupt handler gets
 	   called. */
-	hermes_struct_init(hw, link->io.BasePort1);
+	hermes_struct_init(hw, link->io.BasePort1,
+				HERMES_IO, HERMES_16BIT_REGSPACING);
 
 	/*
 	   This actually configures the PCMCIA socket -- setting up
@@ -618,7 +644,7 @@
 	printk("\n");
 
 	/* And give us the proc nodes for debugging */
-	if (dldwd_proc_dev_init(priv) != 0) {
+	if (orinoco_proc_dev_init(priv) != 0) {
 		printk(KERN_ERR "orinoco_cs: Failed to create /proc node for %s\n",
 		       ndev->name);
 		goto failed;
@@ -627,12 +653,9 @@
 	/* Note to myself : this replace MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT */
 	SET_MODULE_OWNER(ndev);
 	
-	/* Allow cor_reset, /proc & ioctls to act */
-	priv->hw_ready = 1;
-	
-	/* Do a Pcmcia soft reset of the card (optional) */
-	if(reset_cor)
-		dldwd_cs_cor_reset(priv);
+	/* Let reset_cor parameter override determine_firmware()'s guess */
+	if (reset_cor != -1)
+		priv->broken_cor_reset = ! reset_cor;
 
 	/*
 	   At this point, the dev_node_t structure(s) need to be
@@ -642,29 +665,29 @@
 	link->dev = &card->node;
 	link->state &= ~DEV_CONFIG_PENDING;
 
-	TRACE_EXIT("dldwd");
+	TRACE_EXIT("orinoco");
 
 	return;
 
  cs_failed:
 	cs_error(link->handle, last_fn, last_ret);
  failed:
-	dldwd_cs_release((u_long) link);
+	orinoco_cs_release((u_long) link);
 
-	TRACE_EXIT("dldwd");
-}				/* dldwd_cs_config */
+	TRACE_EXIT("orinoco");
+}				/* orinoco_cs_config */
 
 /*======================================================================
-  After a card is removed, dldwd_cs_release() will unregister the
+  After a card is removed, orinoco_cs_release() will unregister the
   device, and release the PCMCIA configuration.  If the device is
   still open, this will be postponed until it is closed.
   ======================================================================*/
 
 static void
-dldwd_cs_release(u_long arg)
+orinoco_cs_release(u_long arg)
 {
 	dev_link_t *link = (dev_link_t *) arg;
-	dldwd_priv_t *priv = link->priv;
+	struct orinoco_private *priv = link->priv;
 
 	TRACE_ENTER(link->dev->dev_name);
 
@@ -681,7 +704,7 @@
 	}
 
 	/* Unregister proc entry */
-	dldwd_proc_dev_cleanup(priv);
+	orinoco_proc_dev_cleanup(priv);
 
 	/* Don't bother checking to see if these succeed or not */
 	CardServices(ReleaseConfiguration, link->handle);
@@ -692,7 +715,7 @@
 	link->state &= ~DEV_CONFIG;
 
 	TRACE_EXIT(link->dev->dev_name);
-}				/* dldwd_cs_release */
+}				/* orinoco_cs_release */
 
 /*======================================================================
   The card status event handler.  Mostly, this schedules other
@@ -705,39 +728,37 @@
   ======================================================================*/
 
 static int
-dldwd_cs_event(event_t event, int priority,
+orinoco_cs_event(event_t event, int priority,
 		       event_callback_args_t * args)
 {
 	dev_link_t *link = args->client_data;
-	dldwd_priv_t *priv = (dldwd_priv_t *)link->priv;
-	struct net_device *dev = &priv->ndev;
+	struct orinoco_private *priv = (struct orinoco_private *)link->priv;
+	struct net_device *dev = priv->ndev;
 
-	TRACE_ENTER("dldwd");
+	TRACE_ENTER("orinoco");
 
 	switch (event) {
 	case CS_EVENT_CARD_REMOVAL:
-		/* FIXME: Erg.. this whole hw_ready thing looks racy
-		   to me.  this may not be fixable without changin the
-		   PCMCIA subsystem, though */
-		priv->hw_ready = 0;
-		dldwd_shutdown(priv);
 		link->state &= ~DEV_PRESENT;
 		if (link->state & DEV_CONFIG) {
 			netif_stop_queue(dev);
+		}
+		orinoco_shutdown(priv);
+		if (link->state & DEV_CONFIG) {
 			netif_device_detach(dev);
 			mod_timer(&link->release, jiffies + HZ / 20);
 		}
 		break;
 	case CS_EVENT_CARD_INSERTION:
 		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-		dldwd_cs_config(link);
+		orinoco_cs_config(link);
 		break;
 	case CS_EVENT_PM_SUSPEND:
 
 		link->state |= DEV_SUSPEND;
 		/* Fall through... */
 	case CS_EVENT_RESET_PHYSICAL:
-		dldwd_shutdown(priv);
+		orinoco_shutdown(priv);
 		/* Mark the device as stopped, to block IO until later */
 
 		if (link->state & DEV_CONFIG) {
@@ -757,13 +778,13 @@
 				     &link->conf);
 
 			if (link->open) {
-				if (dldwd_reset(priv) == 0) {
+				if (orinoco_reset(priv) == 0) {
 					netif_device_attach(dev);
 					netif_start_queue(dev);
 				} else {
 					printk(KERN_ERR "%s: Error resetting device on PCMCIA event\n",
 					       dev->name);
-					dldwd_cs_stop(dev);
+					orinoco_cs_stop(dev);
 				}
 			}
 		}
@@ -774,17 +795,17 @@
 		break;
 	}
 
-	TRACE_EXIT("dldwd");
+	TRACE_EXIT("orinoco");
 
 	return 0;
-}				/* dldwd_cs_event */
+}				/* orinoco_cs_event */
 
 static int __init
-init_dldwd_cs(void)
+init_orinoco_cs(void)
 {
 	servinfo_t serv;
 
-	TRACE_ENTER("dldwd");
+	TRACE_ENTER("orinoco");
 
 	printk(KERN_DEBUG "%s\n", version);
 
@@ -795,17 +816,17 @@
 		return -1;
 	}
 
-	register_pccard_driver(&dev_info, &dldwd_cs_attach, &dldwd_cs_detach);
+	register_pccard_driver(&dev_info, &orinoco_cs_attach, &orinoco_cs_detach);
 
 
-	TRACE_EXIT("dldwd");
+	TRACE_EXIT("orinoco");
 	return 0;
 }
 
 static void __exit
-exit_dldwd_cs(void)
+exit_orinoco_cs(void)
 {
-	TRACE_ENTER("dldwd");
+	TRACE_ENTER("orinoco");
 
 	unregister_pccard_driver(&dev_info);
 
@@ -814,12 +835,12 @@
 	while (dev_list != NULL) {
 		del_timer(&dev_list->release);
 		if (dev_list->state & DEV_CONFIG)
-			dldwd_cs_release((u_long) dev_list);
-		dldwd_cs_detach(dev_list);
+			orinoco_cs_release((u_long) dev_list);
+		orinoco_cs_detach(dev_list);
 	}
 
-	TRACE_EXIT("dldwd");
+	TRACE_EXIT("orinoco");
 }
 
-module_init(init_dldwd_cs);
-module_exit(exit_dldwd_cs);
+module_init(init_orinoco_cs);
+module_exit(exit_orinoco_cs);
diff -Nru a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/wireless/orinoco_pci.c	Tue Apr 30 17:10:25 2002
@@ -0,0 +1,391 @@
+/* orinoco_pci.c 0.01
+ * 
+ * Driver for Prism II devices that have a direct PCI interface
+ * (i.e., not in a Pcmcia or PLX bridge)
+ *
+ * Specifically here we're talking about the Linksys WMP11
+ *
+ * Some of this code is borrowed from orinoco_plx.c
+ *	Copyright (C) 2001 Daniel Barlow <dan@telent.net>
+ * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing
+ * has been copied from it. linux-wlan-ng-0.1.10 is originally :
+ *	Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
+ * The rest is :
+ *	Copyright (C) 2001 Jean Tourrilhes <jt@hpl.hp.com>
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use your
+ * version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+/*
+ * Theory of operation...
+ * -------------------
+ * Maybe you had a look in orinoco_plx. Well, this is totally different...
+ *
+ * The card contains only one PCI region, which contains all the usual
+ * hermes registers.
+ *
+ * The driver will memory map this region in normal memory. Because
+ * the hermes registers are mapped in normal memory and not in ISA I/O
+ * post space, we can't use the usual inw/outw macros and we need to
+ * use readw/writew.
+ * This slight difference force us to compile our own version of
+ * hermes.c with the register access macro changed. That's a bit
+ * hackish but works fine.
+ *
+ * Note that the PCI region is pretty big (4K). That's much more than
+ * the usual set of hermes register (0x0 -> 0x3E). I've got a strong
+ * suspicion that the whole memory space of the adapter is in fact in
+ * this region. Accessing directly the adapter memory instead of going
+ * through the usual register would speed up significantely the
+ * operations...
+ *
+ * Finally, the card looks like this :
+-----------------------
+  Bus  0, device  14, function  0:
+    Network controller: PCI device 1260:3873 (Harris Semiconductor) (rev 1).
+      IRQ 11.
+      Master Capable.  Latency=248.  
+      Prefetchable 32 bit memory at 0xffbcc000 [0xffbccfff].
+-----------------------
+00:0e.0 Network controller: Harris Semiconductor: Unknown device 3873 (rev 01)
+        Subsystem: Unknown device 1737:3874
+        Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B-
+        Status: Cap+ 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
+        Latency: 248 set, cache line size 08
+        Interrupt: pin A routed to IRQ 11
+        Region 0: Memory at ffbcc000 (32-bit, prefetchable) [size=4K]
+        Capabilities: [dc] Power Management version 2
+                Flags: PMEClk- AuxPwr- DSI- D1+ D2+ PME+
+                Status: D0 PME-Enable- DSel=0 DScale=0 PME-
+-----------------------
+ *
+ * That's all..
+ *
+ * Jean II
+ */
+
+#include <linux/config.h>
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/proc_fs.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/wireless.h>
+#include <linux/fcntl.h>
+
+#include "hermes.h"
+#include "orinoco.h"
+
+/* All the magic there is from wlan-ng */
+/* Magic offset of the reset register of the PCI card */
+#define HERMES_PCI_COR		(0x26)
+/* Magic bitmask to reset the card */
+#define HERMES_PCI_COR_MASK	(0x0080)
+/* Magic timeouts for doing the reset.
+ * Those times are straight from wlan-ng, and it is claimed that they
+ * are necessary. Alan will kill me. Take your time and grab a coffee. */
+#define HERMES_PCI_COR_ONT	(250)		/* ms */
+#define HERMES_PCI_COR_OFFT	(500)		/* ms */
+#define HERMES_PCI_COR_BUSYT	(500)		/* ms */
+
+MODULE_AUTHOR("Jean Tourrilhes <jt@hpl.hp.com>");
+MODULE_DESCRIPTION("Driver for wireless LAN cards using direct PCI interface");
+MODULE_LICENSE("Dual MPL/GPL");
+
+static int orinoco_pci_open(struct net_device *dev)
+{
+	struct orinoco_private *priv = (struct orinoco_private *) dev->priv;
+	int err;
+
+	netif_device_attach(dev);
+
+	err = orinoco_reset(priv);
+	if (err)
+		printk(KERN_ERR "%s: orinoco_reset failed in orinoco_pci_open()",
+		       dev->name);
+	else
+		netif_start_queue(dev);
+
+	return err;
+}
+
+static int orinoco_pci_stop(struct net_device *dev)
+{
+	struct orinoco_private *priv = (struct orinoco_private *) dev->priv;
+	netif_stop_queue(dev);
+	orinoco_shutdown(priv);
+	return 0;
+}
+
+static void
+orinoco_pci_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	orinoco_interrupt(irq, (struct orinoco_private *)dev_id, regs);
+}
+
+/*
+ * Do a soft reset of the PCI card using the Configuration Option Register
+ * We need this to get going...
+ * This is the part of the code that is strongly inspired from wlan-ng
+ *
+ * Note : This code is done with irq enabled. This mean that many
+ * interrupts will occur while we are there. This is why we use the
+ * jiffies to regulate time instead of a straight mdelay(). Usually we
+ * need only around 245 iteration of the loop to do 250 ms delay.
+ *
+ * Note bis : Don't try to access HERMES_CMD during the reset phase.
+ * It just won't work !
+ */
+static int
+orinoco_pci_cor_reset(struct orinoco_private *priv)
+{
+	hermes_t *hw = &priv->hw;
+	unsigned long	timeout;
+	u16	reg;
+
+	TRACE_ENTER(priv->ndev->name);
+
+
+	/* Assert the reset until the card notice */
+	hermes_write_regn(hw, PCI_COR, HERMES_PCI_COR_MASK);
+	printk(KERN_NOTICE "Reset done");
+	timeout = jiffies + (HERMES_PCI_COR_ONT * HZ / 1000);
+	while(time_before(jiffies, timeout)) {
+		printk(".");
+		mdelay(1);
+	}
+	printk(";\n");
+	//mdelay(HERMES_PCI_COR_ONT);
+
+	/* Give time for the card to recover from this hard effort */
+	hermes_write_regn(hw, PCI_COR, 0x0000);
+	printk(KERN_NOTICE "Clear Reset");
+	timeout = jiffies + (HERMES_PCI_COR_OFFT * HZ / 1000);
+	while(time_before(jiffies, timeout)) {
+		printk(".");
+		mdelay(1);
+	}
+	printk(";\n");
+	//mdelay(HERMES_PCI_COR_OFFT);
+
+	/* The card is ready when it's no longer busy */
+	timeout = jiffies + (HERMES_PCI_COR_BUSYT * HZ / 1000);
+	reg = hermes_read_regn(hw, CMD);
+	while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) {
+		mdelay(1);
+		reg = hermes_read_regn(hw, CMD);
+	}
+	/* Did we timeout ? */
+	if(time_after_eq(jiffies, timeout)) {
+		printk(KERN_ERR "orinoco_pci: Busy timeout\n");
+		return -ETIMEDOUT;
+	}
+	printk(KERN_NOTICE "pci_cor : reg = 0x%X - %lX - %lX\n", reg, timeout, jiffies);
+
+	TRACE_EXIT(priv->ndev->name);
+
+	return 0;
+}
+
+/*
+ * Initialise a card. Mostly similar to PLX code.
+ */
+static int orinoco_pci_init_one(struct pci_dev *pdev,
+				const struct pci_device_id *ent)
+{
+	int err = 0;
+	unsigned long pci_iorange;
+	u16 *pci_ioaddr = NULL;
+	unsigned long pci_iolen;
+	struct orinoco_private *priv = NULL;
+	struct net_device *dev = NULL;
+	int netdev_registered = 0;
+
+	TRACE_ENTER("orinoco_pci");
+
+	err = pci_enable_device(pdev);
+	if (err)
+		return -EIO;
+
+	/* Resource 0 is mapped to the hermes registers */
+	pci_iorange = pci_resource_start(pdev, 0);
+	pci_iolen = pci_resource_len(pdev, 0);
+	pci_ioaddr = ioremap(pci_iorange, pci_iolen);
+	if (! pci_iorange)
+		goto fail;
+
+	/* Usual setup of structures */
+	dev = alloc_orinocodev(0);
+	if (! dev) {
+		err = -ENOMEM;
+		goto fail;
+	}
+	priv = dev->priv;
+
+	dev->base_addr = (int) pci_ioaddr;
+        dev->mem_start = (unsigned long) pci_iorange;
+        dev->mem_end = ((unsigned long) pci_iorange) + pci_iolen - 1;
+	dev->open = orinoco_pci_open;
+	dev->stop = orinoco_pci_stop;
+/*  	priv->card_reset_handler = orinoco_pci_cor_reset; */
+
+	SET_MODULE_OWNER(dev);
+
+	printk(KERN_DEBUG
+	       "Detected Orinoco/Prism2 PCI device at %s, mem:0x%lX to 0x%lX -> 0x%p, irq:%d\n",
+	       pdev->slot_name, dev->mem_start, dev->mem_end, pci_ioaddr, pdev->irq);
+
+	hermes_struct_init(&(priv->hw), dev->base_addr, HERMES_MEM, HERMES_32BIT_REGSPACING);
+	pci_set_drvdata(pdev, priv);
+
+	err = request_irq(pdev->irq, orinoco_pci_interrupt, SA_SHIRQ, dev->name, priv);
+	if (err) {
+		printk(KERN_ERR "orinoco_pci: Error allocating IRQ %d.\n", pdev->irq);
+		err = -EBUSY;
+		goto fail;
+	}
+	dev->irq = pdev->irq;
+	/* Perform a COR reset to start the card */
+	if(orinoco_pci_cor_reset(priv) != 0) {
+		printk(KERN_ERR "%s: Failed to start the card\n", dev->name);
+		err = -ETIMEDOUT;
+		goto fail;
+	}
+
+	/* Override the normal firmware detection - the Prism 2.5 PCI
+	 * cards look like Lucent firmware but are actually Intersil */
+	priv->firmware_type = FIRMWARE_TYPE_INTERSIL;
+
+	err = register_netdev(dev);
+	if (err)
+		goto fail;
+	netdev_registered = 1;
+
+	err = orinoco_proc_dev_init(priv);
+	if (err) {
+		printk(KERN_ERR "%s: Failed to create /proc node\n", dev->name);
+		err = -EIO;
+		goto fail;
+	}
+
+	TRACE_EXIT("orinoco_pci");
+
+        return 0;               /* succeeded */
+ fail:
+	printk(KERN_DEBUG "orinoco_pci: init_one(), FAIL!\n");
+
+	if (priv) {
+		orinoco_proc_dev_cleanup(priv);
+		if (netdev_registered)
+			unregister_netdev(dev);
+
+		if (dev->irq)
+			free_irq(dev->irq, priv);
+
+		kfree(priv);
+	}
+
+	if (pci_ioaddr)
+		iounmap(pci_ioaddr);
+
+	return err;
+}
+
+static void __devexit orinoco_pci_remove_one(struct pci_dev *pdev)
+{
+	struct orinoco_private *priv = pci_get_drvdata(pdev);
+	struct net_device *dev = priv->ndev;
+
+	TRACE_ENTER("orinoco_pci");
+
+	if (!priv)
+		BUG();
+
+	orinoco_proc_dev_cleanup(priv);
+
+	unregister_netdev(dev);
+
+        if (dev->irq)
+		free_irq(dev->irq, priv);
+
+	if (priv->hw.iobase)
+		iounmap((unsigned char *) priv->hw.iobase);
+
+	kfree(priv);
+
+	pci_disable_device(pdev);
+
+	TRACE_EXIT("orinoco_pci");
+}
+
+
+static struct pci_device_id orinoco_pci_pci_id_table[] __devinitdata = {
+	{0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID,},
+	{0,},
+};
+
+MODULE_DEVICE_TABLE(pci, orinoco_pci_pci_id_table);
+
+static struct pci_driver orinoco_pci_driver = {
+	name:"orinoco_pci",
+	id_table:orinoco_pci_pci_id_table,
+	probe:orinoco_pci_init_one,
+	remove:orinoco_pci_remove_one,
+	suspend:0,
+	resume:0
+};
+
+static int __init orinoco_pci_init(void)
+{
+	return pci_module_init(&orinoco_pci_driver);
+}
+
+extern void __exit orinoco_pci_exit(void)
+{
+	pci_unregister_driver(&orinoco_pci_driver);
+}
+
+module_init(orinoco_pci_init);
+module_exit(orinoco_pci_exit);
+
+/*
+ * Local variables:
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff -Nru a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c
--- a/drivers/net/wireless/orinoco_plx.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/net/wireless/orinoco_plx.c	Tue Apr 30 17:10:25 2002
@@ -1,16 +1,8 @@
-/* orinoco_plx.c 0.01
+/* orinoco_plx.c 0.11a
  * 
  * Driver for Prism II devices which would usually be driven by orinoco_cs,
  * but are connected to the PCI bus by a PLX9052. 
  *
- * Specifically here we're talking about the SMC2602W (EZConnect
- * Wireless PCI Adaptor)
- *
- * The actual driving is done by orinoco.c, this is just resource
- * allocation stuff.  The explanation below is courtesy of Ryan Niemi
- * on the linux-wlan-ng list at
- * http://archives.neohapsis.com/archives/dev/linux-wlan/2001-q1/0026.html
- *
  * Copyright (C) 2001 Daniel Barlow <dan@telent.net>
  *
  * The contents of this file are subject to the Mozilla Public License
@@ -34,6 +26,22 @@
  * provisions above, a recipient may use your version of this file
  * under either the MPL or the GPL.
 
+ * Caution: this is experimental and probably buggy.  For success and
+ * failure reports for different cards and adaptors, see
+ * orinoco_plx_pci_id_table near the end of the file.  If you have a
+ * card we don't have the PCI id for, and looks like it should work,
+ * drop me mail with the id and "it works"/"it doesn't work".
+ *
+ * Note: if everything gets detected fine but it doesn't actually send
+ * or receive packets, your first port of call should probably be to   
+ * try newer firmware in the card.  Especially if you're doing Ad-Hoc
+ * modes
+ *
+ * The actual driving is done by orinoco.c, this is just resource
+ * allocation stuff.  The explanation below is courtesy of Ryan Niemi
+ * on the linux-wlan-ng list at
+ * http://archives.neohapsis.com/archives/dev/linux-wlan/2001-q1/0026.html
+
 The PLX9052-based cards (WL11000 and several others) are a different
 beast than the usual PCMCIA-based PRISM2 configuration expected by
 wlan-ng. Here's the general details on how the WL11000 PCI adapter
@@ -95,14 +103,6 @@
 not have time for a while..
 
 ---end of mail---
-
-  Bus  0, device   4, function  0:
-    Network controller: Unknown vendor Unknown device (rev 2).
-      Vendor id=1638. Device id=1100.
-      Medium devsel.  Fast back-to-back capable.  IRQ 10.  
-      I/O at 0x1000 [0x1001].
-      Non-prefetchable 32 bit memory at 0x40000000 [0x40000000].
-      I/O at 0x10c0 [0x10c1].
 */
 
 #include <linux/config.h>
@@ -129,36 +129,36 @@
 #include <linux/wireless.h>
 #include <linux/fcntl.h>
 
-#include <pcmcia/version.h>
-#include <pcmcia/cs_types.h>
-#include <pcmcia/cs.h>
-#include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
-#include <pcmcia/ds.h>
-#include <pcmcia/bus_ops.h>
 
 #include "hermes.h"
 #include "orinoco.h"
 
+static char version[] __initdata = "orinoco_plx.c 0.11a (Daniel Barlow <dan@telent.net>)";
 MODULE_AUTHOR("Daniel Barlow <dan@telent.net>");
 MODULE_DESCRIPTION("Driver for wireless LAN cards using the PLX9052 PCI bridge");
+#ifdef MODULE_LICENSE
 MODULE_LICENSE("Dual MPL/GPL");
+#endif
 
-static dev_info_t dev_info = "orinoco_plx";
+static char dev_info[] = "orinoco_plx";
 
-#define COR_OFFSET    0x3e0	/* COR attribute offset of Prism2 PC card */
-#define COR_VALUE     0x41	/* Enable PC card with interrupt in level trigger */
+#define COR_OFFSET    (0x3e0 / 2)	/* COR attribute offset of Prism2 PC card */
+#define COR_VALUE     (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */
+
+#define PLX_INTCSR       0x4c /* Interrupt Control and Status Register */
+#define PLX_INTCSR_INTEN (1<<6) /* Interrupt Enable bit */
 
 static int orinoco_plx_open(struct net_device *dev)
 {
-	dldwd_priv_t *priv = (dldwd_priv_t *) dev->priv;
+	struct orinoco_private *priv = (struct orinoco_private *) dev->priv;
 	int err;
 
 	netif_device_attach(dev);
 
-	err = dldwd_reset(priv);
+	err = orinoco_reset(priv);
 	if (err)
-		printk(KERN_ERR "%s: dldwd_reset failed in orinoco_plx_open()",
+		printk(KERN_ERR "%s: orinoco_reset failed in orinoco_plx_open()",
 		       dev->name);
 	else
 		netif_start_queue(dev);
@@ -168,110 +168,204 @@
 
 static int orinoco_plx_stop(struct net_device *dev)
 {
-	dldwd_priv_t *priv = (dldwd_priv_t *) dev->priv;
+	struct orinoco_private *priv = (struct orinoco_private *) dev->priv;
 	netif_stop_queue(dev);
-	dldwd_shutdown(priv);
+	orinoco_shutdown(priv);
 	return 0;
 }
 
 static void
 orinoco_plx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-	dldwd_interrupt(irq, ((struct net_device *) dev_id)->priv, regs);
+	orinoco_interrupt(irq, (struct orinoco_private *)dev_id, regs);
 }
 
+static const u16 cis_magic[] = {
+	0x0001, 0x0003, 0x0000, 0x0000, 0x00ff, 0x0017, 0x0004, 0x0067
+};
+
 static int orinoco_plx_init_one(struct pci_dev *pdev,
 				const struct pci_device_id *ent)
 {
-	struct net_device *dev;
-	unsigned long pccard_ioaddr;
+	int err = 0;
+	u16 *attr_mem = NULL;
+	u32 reg, addr;
+	struct orinoco_private *priv = NULL;
+	unsigned long pccard_ioaddr = 0;
+	unsigned long pccard_iolen = 0;
+	struct net_device *dev = NULL;
+	int netdev_registered = 0;
 	int i;
-	int reg;
-	unsigned char *attr_mem;
-	dldwd_priv_t *priv;
 
-	if ((i = pci_enable_device(pdev)))
+	TRACE_ENTER("orinoco_plx");
+
+	err = pci_enable_device(pdev);
+	if (err)
 		return -EIO;
 
 	/* Resource 2 is mapped to the PCMCIA space */
-	attr_mem = ioremap(pci_resource_start(pdev, 2), 0x1000);
-	/* and 3 to the PCMCIA slot I/O address space */
-	pccard_ioaddr = pci_resource_start(pdev, 3);
+	attr_mem = ioremap(pci_resource_start(pdev, 2), PAGE_SIZE);
+	if (! attr_mem)
+		goto fail;
+
+	printk(KERN_DEBUG "orinoco_plx: CIS: ");
+	for (i = 0; i < 16; i++) {
+		printk("%02X:", (int)attr_mem[i]);
+	}
+	printk("\n");
 
 	/* Verify whether PC card is present */
-	if (attr_mem[0] != 0x01 || attr_mem[2] != 0x03 ||
-	    attr_mem[4] != 0x00 || attr_mem[6] != 0x00 ||
-	    attr_mem[8] != 0xFF || attr_mem[10] != 0x17 ||
-	    attr_mem[12] != 0x04 || attr_mem[14] != 0x67) {
+	/* FIXME: we probably need to be smarted about this */
+	if (memcmp(attr_mem, cis_magic, sizeof(cis_magic)) != 0) {
 		printk(KERN_ERR "orinoco_plx: The CIS value of Prism2 PC card is invalid.\n");
-		return -EIO;
+		err = -EIO;
+		goto fail;
 	}
+
 	/* PCMCIA COR is the first byte following CIS: this write should
 	 * enable I/O mode and select level-triggered interrupts */
 	attr_mem[COR_OFFSET] = COR_VALUE;
+	mdelay(1);
 	reg = attr_mem[COR_OFFSET];
-	/* assert(reg==COR_VALUE); doesn't work */
-	iounmap(attr_mem);	/* done with this now, it seems */
-	if (!request_region(pccard_ioaddr,
-			    pci_resource_len(pdev, 3), dev_info)) {
+	if (reg != COR_VALUE) {
+		printk(KERN_ERR "orinoco_plx: Error setting COR value (reg=%x)\n", reg);
+		goto fail;
+	}			
+
+	iounmap(attr_mem);
+	attr_mem = NULL; /* done with this now, it seems */
+
+	/* bjoern: We need to tell the card to enable interrupts, in
+	   case the serial eprom didn't do this already. See the
+	   PLX9052 data book, p8-1 and 8-24 for reference. */
+	addr = pci_resource_start(pdev, 1);
+	reg = 0;
+	reg = inl(addr+PLX_INTCSR);
+	if(reg & PLX_INTCSR_INTEN)
+		printk(KERN_DEBUG "orinoco_plx: "
+		       "Local Interrupt already enabled\n");
+	else {
+		reg |= PLX_INTCSR_INTEN;
+		outl(reg, addr+PLX_INTCSR);
+		reg = inl(addr+PLX_INTCSR);
+		if(!(reg & PLX_INTCSR_INTEN)) {
+			printk(KERN_ERR "orinoco_plx: "
+			       "Couldn't enable Local Interrupts\n");
+			goto fail;
+		}
+	}
+
+	/* and 3 to the PCMCIA slot I/O address space */
+	pccard_ioaddr = pci_resource_start(pdev, 3);
+	pccard_iolen = pci_resource_len(pdev, 3);
+	if (! request_region(pccard_ioaddr, pccard_iolen, dev_info)) {
 		printk(KERN_ERR "orinoco_plx: I/O resource 0x%lx @ 0x%lx busy\n",
-		       pci_resource_len(pdev, 3), pccard_ioaddr);
-		return -EBUSY;
+		       pccard_iolen, pccard_ioaddr);
+		pccard_ioaddr = 0;
+		err = -EBUSY;
+		goto fail;
 	}
-	if (!(priv = kmalloc(sizeof(*priv), GFP_KERNEL)))
-		return -ENOMEM;
-	memset(priv, 0, sizeof(*priv));
-	dev = &priv->ndev;
 
-	dldwd_setup(priv);	/* XXX clean up if <0 */
-	dev->irq = pdev->irq;
+	dev = alloc_orinocodev(0);
+	if (! dev) {
+		err = -ENOMEM;
+		goto fail;
+	}
+
+	priv = dev->priv;
 	dev->base_addr = pccard_ioaddr;
 	dev->open = orinoco_plx_open;
 	dev->stop = orinoco_plx_stop;
-	priv->card_reset_handler = NULL; /* We have no reset handler */
+	SET_MODULE_OWNER(dev);
 
 	printk(KERN_DEBUG
-	       "Detected Orinoco/Prism2 PCI device at %s, mem:0x%lx, irq:%d, io addr:0x%lx\n",
-	       pdev->slot_name, (long) attr_mem, pdev->irq, pccard_ioaddr);
+	       "Detected Orinoco/Prism2 PLX device at %s irq:%d, io addr:0x%lx\n",
+	       pdev->slot_name, pdev->irq, pccard_ioaddr);
 
-	hermes_struct_init(&(priv->hw), dev->base_addr);	/* XXX */
-	dev->name[0] = '\0';	/* name defaults to ethX */
-	register_netdev(dev);
-	request_irq(pdev->irq, orinoco_plx_interrupt, SA_SHIRQ, dev->name,
-		    dev);
-	if (dldwd_proc_dev_init(priv) != 0) {
-		printk(KERN_ERR "%s: Failed to create /proc node\n", dev->name);
-		return -EIO;
+	hermes_struct_init(&(priv->hw), dev->base_addr,
+			HERMES_IO, HERMES_16BIT_REGSPACING);
+	pci_set_drvdata(pdev, priv);
+
+	err = request_irq(pdev->irq, orinoco_plx_interrupt, SA_SHIRQ, dev->name, priv);
+	if (err) {
+		printk(KERN_ERR "orinoco_plx: Error allocating IRQ %d.\n", pdev->irq);
+		err = -EBUSY;
+		goto fail;
 	}
+	dev->irq = pdev->irq;
 
-	SET_MODULE_OWNER(dev);
-	priv->hw_ready = 1;
+	err = register_netdev(dev);
+	if (err)
+		goto fail;
+	netdev_registered = 1;
+
+	err = orinoco_proc_dev_init(priv);
+	if (err)
+		goto fail;
+
+	TRACE_EXIT("orinoco_plx");
 
-	/* if(reset_cor) dldwd_cs_cor_reset(priv); */
 	return 0;		/* succeeded */
+
+ fail:	
+	printk(KERN_DEBUG "orinoco_plx: init_one(), FAIL!\n");
+
+	if (priv) {
+		orinoco_proc_dev_cleanup(priv);
+
+		if (netdev_registered)
+			unregister_netdev(dev);
+		
+		if (dev->irq)
+			free_irq(dev->irq, priv);
+		
+		kfree(priv);
+	}
+
+	if (pccard_ioaddr)
+		release_region(pccard_ioaddr, pccard_iolen);
+
+	if (attr_mem)
+		iounmap(attr_mem);
+
+	pci_disable_device(pdev);
+
+	TRACE_EXIT("orinoco_plx");
+	
+	return err;
 }
 
 static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev)
 {
-	struct net_device *dev = pci_get_drvdata(pdev);
-	dldwd_priv_t *priv = dev->priv;
+	struct orinoco_private *priv = pci_get_drvdata(pdev);
+	struct net_device *dev = priv->ndev;
+
+	TRACE_ENTER("orinoco_plx");
 
-	if (!dev)
+	if (!priv)
 		BUG();
 
-	dldwd_proc_dev_cleanup(priv);
-	free_irq(dev->irq, dev);
+	orinoco_proc_dev_cleanup(priv);
+
 	unregister_netdev(dev);
-	release_region(dev->base_addr, 0x40);
-	kfree(dev->priv);
-	pci_set_drvdata(pdev, NULL);
+		
+	if (dev->irq)
+		free_irq(dev->irq, priv);
+		
+	kfree(priv);
+
+	release_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3));
+
+	pci_disable_device(pdev);
+
+	TRACE_EXIT("orinoco_plx");
 }
 
+
 static struct pci_device_id orinoco_plx_pci_id_table[] __devinitdata = {
+	{0x111a, 0x1023, PCI_ANY_ID, PCI_ANY_ID,},	/* Siemens SpeedStream SS1023 */
 	{0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,},	/* Netgear MA301 */
-#if 0
-	{0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,},	/* Correga */
-#endif
+	{0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,},	/* Correga  - does this work? */
 	{0x1638, 0x1100, PCI_ANY_ID, PCI_ANY_ID,},	/* SMC EZConnect SMC2602W,
 							   Eumitcom PCI WL11000,
 							   Addtron AWA-100*/
@@ -279,26 +373,34 @@
 	{0x16ab, 0x1101, PCI_ANY_ID, PCI_ANY_ID,},	/* Reported working, but unknown */
 	{0x16ab, 0x1102, PCI_ANY_ID, PCI_ANY_ID,},	/* Linksys WDT11 */
 	{0x16ec, 0x3685, PCI_ANY_ID, PCI_ANY_ID,},	/* USR 2415 */
-	{0xec80, 0xec00, PCI_ANY_ID, PCI_ANY_ID,}, 	/* Belkin F5D6000 */
+	{0xec80, 0xec00, PCI_ANY_ID, PCI_ANY_ID,},	/* Belkin F5D6000 tested by
+							   Brendan W. McAdams <rit@jacked-in.org> */
+	{0x126c, 0x8030, PCI_ANY_ID, PCI_ANY_ID,},	/* Nortel emobility */
 	{0,},
 };
+
 MODULE_DEVICE_TABLE(pci, orinoco_plx_pci_id_table);
 
 static struct pci_driver orinoco_plx_driver = {
-	name:		"orinoco_plx",
-	id_table:	orinoco_plx_pci_id_table,
-	probe:		orinoco_plx_init_one,
-	remove:		__devexit_p(orinoco_plx_remove_one),
+	name:"orinoco_plx",
+	id_table:orinoco_plx_pci_id_table,
+	probe:orinoco_plx_init_one,
+	remove:orinoco_plx_remove_one,
+	suspend:0,
+	resume:0
 };
 
 static int __init orinoco_plx_init(void)
 {
+	printk(KERN_DEBUG "%s\n", version);
 	return pci_module_init(&orinoco_plx_driver);
 }
 
 extern void __exit orinoco_plx_exit(void)
 {
 	pci_unregister_driver(&orinoco_plx_driver);
+	current->state = TASK_UNINTERRUPTIBLE;
+	schedule_timeout(HZ);
 }
 
 module_init(orinoco_plx_init);
diff -Nru a/drivers/pci/pci.ids b/drivers/pci/pci.ids
--- a/drivers/pci/pci.ids	Tue Apr 30 17:10:23 2002
+++ b/drivers/pci/pci.ids	Tue Apr 30 17:10:23 2002
@@ -5097,9 +5097,11 @@
 	244b  82820 820 (Camino 2) Chipset IDE U100
 	244c  82820 820 (Camino 2) Chipset ISA Bridge (ICH2-M)
 	244e  82820 820 (Camino 2) Chipset PCI
+	245b  82801E C-ICH IDE
 	2485  AC'97 Audio Controller
 	248a  82801CAM ICH3-M IDE
 	248b  82801CA ICH3 IDE
+	24cb  82801DB ICH4 IDE
 	2500  82820 820 (Camino) Chipset Host Bridge (MCH)
 		1043 801c  P3C-2000 system chipset
 	2501  82820 820 (Camino) Chipset Host Bridge (MCH)
diff -Nru a/drivers/pnp/pnpbios_core.c b/drivers/pnp/pnpbios_core.c
--- a/drivers/pnp/pnpbios_core.c	Tue Apr 30 17:10:23 2002
+++ b/drivers/pnp/pnpbios_core.c	Tue Apr 30 17:10:23 2002
@@ -113,12 +113,12 @@
 __asm__(
 	".text			\n"
 	__ALIGN_STR "\n"
-	SYMBOL_NAME_STR(pnp_bios_callfunc) ":\n"
+	"pnp_bios_callfunc:\n"
 	"	pushl %edx	\n"
 	"	pushl %ecx	\n"
 	"	pushl %ebx	\n"
 	"	pushl %eax	\n"
-	"	lcallw " SYMBOL_NAME_STR(pnp_bios_callpoint) "\n"
+	"	lcallw pnp_bios_callpoint\n"
 	"	addl $16, %esp	\n"
 	"	lret		\n"
 	".previous		\n"
diff -Nru a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
--- a/drivers/scsi/ide-scsi.c	Tue Apr 30 17:10:23 2002
+++ b/drivers/scsi/ide-scsi.c	Tue Apr 30 17:10:23 2002
@@ -59,7 +59,6 @@
 	int request_transfer;			/* Bytes to transfer */
 	int actually_transferred;		/* Bytes actually transferred */
 	int buffer_size;			/* Size of our data buffer */
-	struct request *rq;			/* The corresponding request */
 	byte *buffer;				/* Data buffer */
 	byte *current_position;			/* Pointer into the above buffer */
 	struct scatterlist *sg;			/* Scatter gather table */
@@ -259,10 +258,9 @@
 	printk("]\n");
 }
 
-static int idescsi_end_request(ide_drive_t *drive, int uptodate)
+static int idescsi_end_request(struct ata_device *drive, struct request *rq, int uptodate)
 {
 	idescsi_scsi_t *scsi = drive->driver_data;
-	struct request *rq = HWGROUP(drive)->rq;
 	idescsi_pc_t *pc = (idescsi_pc_t *) rq->special;
 	int log = test_bit(IDESCSI_LOG_CMD, &scsi->log);
 	struct Scsi_Host *host;
@@ -270,7 +268,7 @@
 	unsigned long flags;
 
 	if (!(rq->flags & REQ_SPECIAL)) {
-		ide_end_request(drive, uptodate);
+		ide_end_request(drive, rq, uptodate);
 		return 0;
 	}
 	ide_end_drive_cmd (drive, 0, 0);
@@ -313,13 +311,12 @@
 /*
  *	Our interrupt handler.
  */
-static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
+static ide_startstop_t idescsi_pc_intr(struct ata_device *drive, struct request *rq)
 {
 	idescsi_scsi_t *scsi = drive->driver_data;
 	byte status, ireason;
 	int bcount;
 	idescsi_pc_t *pc=scsi->pc;
-	struct request *rq = pc->rq;
 	unsigned int temp;
 
 #if IDESCSI_DEBUG_LOG
@@ -331,7 +328,7 @@
 		printk ("ide-scsi: %s: DMA complete\n", drive->name);
 #endif /* IDESCSI_DEBUG_LOG */
 		pc->actually_transferred=pc->request_transfer;
-		(void) drive->channel->dmaproc(ide_dma_end, drive);
+		(void) drive->channel->udma(ide_dma_end, drive, NULL);
 	}
 
 	status = GET_STAT();						/* Clear the interrupt */
@@ -342,7 +339,7 @@
 		ide__sti();
 		if (status & ERR_STAT)
 			rq->errors++;
-		idescsi_end_request(drive, 1);
+		idescsi_end_request(drive, rq, 1);
 		return ide_stopped;
 	}
 	bcount = IN_BYTE (IDE_BCOUNTH_REG) << 8 | IN_BYTE (IDE_BCOUNTL_REG);
@@ -369,7 +366,7 @@
 				pc->actually_transferred += temp;
 				pc->current_position += temp;
 				idescsi_discard_data (drive,bcount - temp);
-				ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);
+				ide_set_handler(drive, idescsi_pc_intr, get_timeout(pc), NULL);
 				return ide_started;
 			}
 #if IDESCSI_DEBUG_LOG
@@ -393,11 +390,11 @@
 	pc->actually_transferred+=bcount;				/* Update the current position */
 	pc->current_position+=bcount;
 
-	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);	/* And set the interrupt handler again */
+	ide_set_handler(drive, idescsi_pc_intr, get_timeout(pc), NULL);	/* And set the interrupt handler again */
 	return ide_started;
 }
 
-static ide_startstop_t idescsi_transfer_pc (ide_drive_t *drive)
+static ide_startstop_t idescsi_transfer_pc(struct ata_device *drive, struct request *rq)
 {
 	idescsi_scsi_t *scsi = drive->driver_data;
 	idescsi_pc_t *pc = scsi->pc;
@@ -413,7 +410,7 @@
 		printk (KERN_ERR "ide-scsi: (IO,CoD) != (0,1) while issuing a packet command\n");
 		return ide_stopped;
 	}
-	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);	/* Set the interrupt routine */
+	ide_set_handler(drive, idescsi_pc_intr, get_timeout(pc), NULL);	/* Set the interrupt routine */
 	atapi_write(drive, scsi->pc->c, 12);			/* Send the actual packet */
 	return ide_started;
 }
@@ -421,11 +418,10 @@
 /*
  *	Issue a packet command
  */
-static ide_startstop_t idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc)
+static ide_startstop_t idescsi_issue_pc(struct ata_device *drive, struct request *rq, idescsi_pc_t *pc)
 {
 	idescsi_scsi_t *scsi = drive->driver_data;
 	int bcount;
-	struct request *rq = pc->rq;
 	int dma_ok = 0;
 
 	scsi->pc=pc;							/* Set the current packet command */
@@ -434,7 +430,7 @@
 	bcount = min(pc->request_transfer, 63 * 1024);		/* Request to transfer the entire buffer at once */
 
 	if (drive->using_dma && rq->bio)
-		dma_ok = !drive->channel->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
+		dma_ok = !drive->channel->udma(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive, rq);
 
 	SELECT_DRIVE(drive->channel, drive);
 	if (IDE_CONTROL_REG)
@@ -445,15 +441,15 @@
 
 	if (dma_ok) {
 		set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
-		(void) drive->channel->dmaproc(ide_dma_begin, drive);
+		(void) drive->channel->udma(ide_dma_begin, drive, NULL);
 	}
 	if (test_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
-		ide_set_handler (drive, &idescsi_transfer_pc, get_timeout(pc), NULL);
+		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);
-		return idescsi_transfer_pc (drive);
+		return idescsi_transfer_pc(drive, rq);
 	}
 }
 
@@ -468,10 +464,10 @@
 #endif /* IDESCSI_DEBUG_LOG */
 
 	if (rq->flags & REQ_SPECIAL) {
-		return idescsi_issue_pc(drive, (idescsi_pc_t *) rq->special);
+		return idescsi_issue_pc(drive, rq, (idescsi_pc_t *) rq->special);
 	}
 	blk_dump_rq_flags(rq, "ide-scsi: unsup command");
-	idescsi_end_request(drive, 0);
+	idescsi_end_request(drive, rq, 0);
 	return ide_stopped;
 }
 
@@ -760,7 +756,6 @@
 
 	memset (pc->c, 0, 12);
 	pc->flags = 0;
-	pc->rq = rq;
 	memcpy (pc->c, cmd->cmnd, cmd->cmd_len);
 	if (cmd->use_sg) {
 		pc->buffer = NULL;
diff -Nru a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c
--- a/drivers/scsi/seagate.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/scsi/seagate.c	Tue Apr 30 17:10:25 2002
@@ -1285,8 +1285,8 @@
 							/* Test for any data here at all. */
 							"orl %%ecx, %%ecx\n\t"
 							"jz 2f\n\t" "cld\n\t"
-/*                    "movl " SYMBOL_NAME_STR(st0x_cr_sr) ", %%ebx\n\t"  */
-/*                    "movl " SYMBOL_NAME_STR(st0x_dr) ", %%edi\n\t"  */
+/*                    "movl st0x_cr_sr, %%ebx\n\t"  */
+/*                    "movl st0x_dr, %%edi\n\t"  */
 							"1:\t"
 							"movb (%%ebx), %%al\n\t"
 							/* Test for BSY */
@@ -1461,8 +1461,8 @@
 							/* Test for room to read */
 							"orl %%ecx, %%ecx\n\t"
 							"jz 2f\n\t" "cld\n\t"
-/*                "movl " SYMBOL_NAME_STR(st0x_cr_sr) ", %%esi\n\t"  */
-/*                "movl " SYMBOL_NAME_STR(st0x_dr) ", %%ebx\n\t"  */
+/*                "movl st0x_cr_sr, %%esi\n\t"  */
+/*                "movl st0x_dr, %%ebx\n\t"  */
 							"1:\t"
 							"movb (%%esi), %%al\n\t"
 							/* Test for BSY */
diff -Nru a/drivers/sgi/char/sgiserial.c b/drivers/sgi/char/sgiserial.c
--- a/drivers/sgi/char/sgiserial.c	Tue Apr 30 17:10:25 2002
+++ b/drivers/sgi/char/sgiserial.c	Tue Apr 30 17:10:25 2002
@@ -423,7 +423,8 @@
 			show_state();
 			return;
 		} else if (ch == 2) {
-			show_buffers();
+			printk("%ld buffermem pages\n",
+					nr_buffermem_pages());
 			return;
 		}
 	}
diff -Nru a/drivers/video/Makefile b/drivers/video/Makefile
--- a/drivers/video/Makefile	Tue Apr 30 17:10:23 2002
+++ b/drivers/video/Makefile	Tue Apr 30 17:10:23 2002
@@ -15,7 +15,7 @@
 		  fbcon-iplan2p8.o fbcon-vga-planes.o fbcon-cfb16.o \
 		  fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o \
 		  fbcon-cfb8.o fbcon-mac.o fbcon-mfb.o \
-		  cyber2000fb.o sa1100fb.o fbcon-hga.o
+		  cyber2000fb.o sa1100fb.o fbcon-hga.o fbgen.o
 
 # Each configuration option enables a list of files.
 
diff -Nru a/fs/Makefile b/fs/Makefile
--- a/fs/Makefile	Tue Apr 30 17:10:23 2002
+++ b/fs/Makefile	Tue Apr 30 17:10:23 2002
@@ -14,7 +14,8 @@
 		bio.o super.o block_dev.o char_dev.o stat.o exec.o pipe.o \
 		namei.o fcntl.o ioctl.o readdir.o select.o fifo.o locks.o \
 		dcache.o inode.o attr.o bad_inode.o file.o iobuf.o dnotify.o \
-		filesystems.o namespace.o seq_file.o xattr.o libfs.o
+		filesystems.o namespace.o seq_file.o xattr.o libfs.o \
+		fs-writeback.o
 
 ifneq ($(CONFIG_NFSD),n)
 ifneq ($(CONFIG_NFSD),)
diff -Nru a/fs/adfs/dir.c b/fs/adfs/dir.c
--- a/fs/adfs/dir.c	Tue Apr 30 17:10:23 2002
+++ b/fs/adfs/dir.c	Tue Apr 30 17:10:23 2002
@@ -36,6 +36,8 @@
 	struct adfs_dir dir;
 	int ret = 0;
 
+	lock_kernel();	
+
 	if (filp->f_pos >> 32)
 		goto out;
 
@@ -77,6 +79,7 @@
 	ops->free(&dir);
 
 out:
+	unlock_kernel();
 	return ret;
 }
 
diff -Nru a/fs/affs/dir.c b/fs/affs/dir.c
--- a/fs/affs/dir.c	Tue Apr 30 17:10:25 2002
+++ b/fs/affs/dir.c	Tue Apr 30 17:10:25 2002
@@ -22,6 +22,7 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/amigaffs.h>
+#include <linux/smp_lock.h>
 
 static int affs_readdir(struct file *, void *, filldir_t);
 
@@ -63,6 +64,8 @@
 	int			 stored;
 	int			 res;
 
+	lock_kernel();
+	
 	pr_debug("AFFS: readdir(ino=%lu,f_pos=%lx)\n",inode->i_ino,(unsigned long)filp->f_pos);
 
 	stored = 0;
@@ -158,6 +161,7 @@
 	affs_brelse(dir_bh);
 	affs_brelse(fh_bh);
 	affs_unlock_dir(inode);
+	unlock_kernel();
 	pr_debug("AFFS: readdir()=%d\n", stored);
 	return res;
 }
diff -Nru a/fs/affs/file.c b/fs/affs/file.c
--- a/fs/affs/file.c	Tue Apr 30 17:10:25 2002
+++ b/fs/affs/file.c	Tue Apr 30 17:10:25 2002
@@ -361,7 +361,7 @@
 		u32 blocknr = affs_alloc_block(inode, ext_bh->b_blocknr);
 		if (!blocknr)
 			goto err_alloc;
-		bh_result->b_state |= (1UL << BH_New);
+		set_buffer_new(bh_result);
 		AFFS_I(inode)->mmu_private += AFFS_SB(sb)->s_data_blksize;
 		AFFS_I(inode)->i_blkcnt++;
 
@@ -400,7 +400,7 @@
 	return PTR_ERR(ext_bh);
 err_alloc:
 	brelse(ext_bh);
-	bh_result->b_state &= ~(1UL << BH_Mapped);
+	clear_buffer_mapped(bh_result);
 	bh_result->b_bdev = NULL;
 	// unlock cache
 	affs_unlock_ext(inode);
@@ -618,7 +618,7 @@
 	err = affs_do_readpage_ofs(file, page, 0, to);
 	if (!err)
 		SetPageUptodate(page);
-	UnlockPage(page);
+	unlock_page(page);
 	return err;
 }
 
@@ -630,7 +630,7 @@
 	int err = 0;
 
 	pr_debug("AFFS: prepare_write(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to);
-	if (Page_Uptodate(page))
+	if (PageUptodate(page))
 		return 0;
 
 	size = inode->i_size;
@@ -701,7 +701,7 @@
 		if (IS_ERR(bh))
 			goto out;
 		memcpy(AFFS_DATA(bh), data + from, bsize);
-		if (bh->b_state & (1UL << BH_New)) {
+		if (buffer_new(bh)) {
 			AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
 			AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino);
 			AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
@@ -730,7 +730,7 @@
 			goto out;
 		tmp = min(bsize, to - from);
 		memcpy(AFFS_DATA(bh), data + from, tmp);
-		if (bh->b_state & (1UL << BH_New)) {
+		if (buffer_new(bh)) {
 			AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
 			AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino);
 			AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
@@ -830,7 +830,7 @@
 		res = mapping->a_ops->prepare_write(NULL, page, size, size);
 		if (!res)
 			res = mapping->a_ops->commit_write(NULL, page, size, size);
-		UnlockPage(page);
+		unlock_page(page);
 		page_cache_release(page);
 		mark_inode_dirty(inode);
 		unlock_kernel();
diff -Nru a/fs/affs/symlink.c b/fs/affs/symlink.c
--- a/fs/affs/symlink.c	Tue Apr 30 17:10:25 2002
+++ b/fs/affs/symlink.c	Tue Apr 30 17:10:25 2002
@@ -67,12 +67,12 @@
 	unlock_kernel();
 	SetPageUptodate(page);
 	kunmap(page);
-	UnlockPage(page);
+	unlock_page(page);
 	return 0;
 fail:
 	SetPageError(page);
 	kunmap(page);
-	UnlockPage(page);
+	unlock_page(page);
 	return err;
 }
 
diff -Nru a/fs/autofs/root.c b/fs/autofs/root.c
--- a/fs/autofs/root.c	Tue Apr 30 17:10:25 2002
+++ b/fs/autofs/root.c	Tue Apr 30 17:10:25 2002
@@ -47,6 +47,8 @@
 	struct inode * inode = filp->f_dentry->d_inode;
 	off_t onr, nr;
 
+	lock_kernel();
+
 	sbi = autofs_sbi(inode->i_sb);
 	dirhash = &sbi->dirhash;
 	nr = filp->f_pos;
@@ -55,25 +57,27 @@
 	{
 	case 0:
 		if (filldir(dirent, ".", 1, nr, inode->i_ino, DT_DIR) < 0)
-			return 0;
+			goto out;
 		filp->f_pos = ++nr;
 		/* fall through */
 	case 1:
 		if (filldir(dirent, "..", 2, nr, inode->i_ino, DT_DIR) < 0)
-			return 0;
+			goto out;
 		filp->f_pos = ++nr;
 		/* fall through */
 	default:
 		while ( onr = nr, ent = autofs_hash_enum(dirhash,&nr,ent) ) {
 			if ( !ent->dentry || d_mountpoint(ent->dentry) ) {
 				if (filldir(dirent,ent->name,ent->len,onr,ent->ino,DT_UNKNOWN) < 0)
-					return 0;
+					goto out;
 				filp->f_pos = nr;
 			}
 		}
 		break;
 	}
 
+out:
+	unlock_kernel();
 	return 0;
 }
 
diff -Nru a/fs/bad_inode.c b/fs/bad_inode.c
--- a/fs/bad_inode.c	Tue Apr 30 17:10:25 2002
+++ b/fs/bad_inode.c	Tue Apr 30 17:10:25 2002
@@ -9,6 +9,7 @@
 #include <linux/fs.h>
 #include <linux/stat.h>
 #include <linux/time.h>
+#include <linux/smp_lock.h>
 
 /*
  * The follow_link operation is special: it must behave as a no-op
diff -Nru a/fs/bfs/dir.c b/fs/bfs/dir.c
--- a/fs/bfs/dir.c	Tue Apr 30 17:10:25 2002
+++ b/fs/bfs/dir.c	Tue Apr 30 17:10:25 2002
@@ -32,9 +32,12 @@
 	unsigned int offset;
 	int block;
 
+	lock_kernel();
+
 	if (f->f_pos & (BFS_DIRENT_SIZE-1)) {
 		printf("Bad f_pos=%08lx for %s:%08lx\n", (unsigned long)f->f_pos, 
 			dir->i_sb->s_id, dir->i_ino);
+		unlock_kernel();
 		return -EBADF;
 	}
 
@@ -52,6 +55,7 @@
 				int size = strnlen(de->name, BFS_NAMELEN);
 				if (filldir(dirent, de->name, size, f->f_pos, de->ino, DT_UNKNOWN) < 0) {
 					brelse(bh);
+					unlock_kernel();
 					return 0;
 				}
 			}
@@ -62,6 +66,7 @@
 	}
 
 	UPDATE_ATIME(dir);
+	unlock_kernel();
 	return 0;	
 }
 
diff -Nru a/fs/block_dev.c b/fs/block_dev.c
--- a/fs/block_dev.c	Tue Apr 30 17:10:25 2002
+++ b/fs/block_dev.c	Tue Apr 30 17:10:25 2002
@@ -84,7 +84,7 @@
 
 	/* Ok, we're actually changing the blocksize.. */
 	bdev = bdget(kdev_t_to_nr(dev));
-	sync_buffers(bdev, 2);
+	sync_blockdev(bdev);
 	blksize_size[major(dev)][minor(dev)] = size;
 	bdev->bd_inode->i_blkbits = blksize_bits(size);
 	kill_bdev(bdev);
@@ -119,7 +119,7 @@
 
 	bh->b_bdev = inode->i_bdev;
 	bh->b_blocknr = iblock;
-	bh->b_state |= 1UL << BH_Mapped;
+	set_buffer_mapped(bh);
 	return 0;
 }
 
@@ -180,22 +180,6 @@
 	return retval;
 }
 	
-
-static int __block_fsync(struct inode * inode)
-{
-	int ret, err;
-
-	ret = filemap_fdatasync(inode->i_mapping);
-	err = sync_buffers(inode->i_bdev, 1);
-	if (err && !ret)
-		ret = err;
-	err = filemap_fdatawait(inode->i_mapping);
-	if (err && !ret)
-		ret = err;
-
-	return ret;
-}
-
 /*
  *	Filp may be NULL when we are called by an msync of a vma
  *	since the vma has no handle.
@@ -205,7 +189,7 @@
 {
 	struct inode * inode = dentry->d_inode;
 
-	return __block_fsync(inode);
+	return sync_blockdev(inode->i_bdev);
 }
 
 /*
@@ -349,6 +333,8 @@
 		struct inode *inode = new_inode(bd_mnt->mnt_sb);
 		if (inode) {
 			kdev_t kdev = to_kdev_t(dev);
+			unsigned long *ra_pages;
+
 			atomic_set(&new_bdev->bd_count,1);
 			new_bdev->bd_dev = dev;
 			new_bdev->bd_op = NULL;
@@ -360,6 +346,10 @@
 			inode->i_bdev = new_bdev;
 			inode->i_data.a_ops = &def_blk_aops;
 			inode->i_data.gfp_mask = GFP_USER;
+			ra_pages = blk_get_ra_pages(kdev);
+			if (ra_pages == NULL)
+				ra_pages = &default_ra_pages;
+			inode->i_data.ra_pages = ra_pages;
 			spin_lock(&bdev_lock);
 			bdev = bdfind(dev, head);
 			if (!bdev) {
@@ -698,10 +688,8 @@
 	lock_kernel();
 	switch (kind) {
 	case BDEV_FILE:
-		__block_fsync(bd_inode);
-		break;
 	case BDEV_FS:
-		fsync_no_super(bdev);
+		sync_blockdev(bd_inode->i_bdev);
 		break;
 	}
 	if (!--bdev->bd_openers)
@@ -753,6 +741,8 @@
 	sync_page: block_sync_page,
 	prepare_write: blkdev_prepare_write,
 	commit_write: blkdev_commit_write,
+	writeback_mapping: generic_writeback_mapping,
+	vm_writeback: generic_vm_writeback,
 	direct_IO: blkdev_direct_IO,
 };
 
diff -Nru a/fs/buffer.c b/fs/buffer.c
--- a/fs/buffer.c	Tue Apr 30 17:10:23 2002
+++ b/fs/buffer.c	Tue Apr 30 17:10:23 2002
@@ -1,150 +1,151 @@
 /*
  *  linux/fs/buffer.c
  *
- *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 1991, 1992, 2002  Linus Torvalds
  */
 
 /*
- *  'buffer.c' implements the buffer-cache functions. Race-conditions have
- * been avoided by NEVER letting an interrupt change a buffer (except for the
- * data, of course), but instead letting the caller do it.
- */
-
-/* Start bdflush() with kernel_thread not syscall - Paul Gortmaker, 12/95 */
-
-/* Removed a lot of unnecessary code and simplified things now that
+ * Start bdflush() with kernel_thread not syscall - Paul Gortmaker, 12/95
+ *
+ * Removed a lot of unnecessary code and simplified things now that
  * the buffer cache isn't our primary cache - Andrew Tridgell 12/96
+ *
+ * Speed up hash, lru, and free list operations.  Use gfp() for allocating
+ * hash table, use SLAB cache for buffer heads. SMP threading.  -DaveM
+ *
+ * Added 32k buffer block sizes - these are required older ARM systems. - RMK
+ *
+ * async buffer flushing, 1999 Andrea Arcangeli <andrea@suse.de>
  */
 
-/* Speed up hash, lru, and free list operations.  Use gfp() for allocating
- * hash table, use SLAB cache for buffer heads. -DaveM
- */
-
-/* Added 32k buffer block sizes - these are required older ARM systems.
- * - RMK
- */
-
-/* Thread it... -DaveM */
-
-/* async buffer flushing, 1999 Andrea Arcangeli <andrea@suse.de> */
-
 #include <linux/config.h>
-#include <linux/time.h>
+#include <linux/kernel.h>
 #include <linux/fs.h>
+#include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/locks.h>
-#include <linux/errno.h>
-#include <linux/swap.h>
-#include <linux/swapctl.h>
 #include <linux/smp_lock.h>
-#include <linux/vmalloc.h>
 #include <linux/blkdev.h>
-#include <linux/sysrq.h>
 #include <linux/file.h>
-#include <linux/init.h>
 #include <linux/quotaops.h>
 #include <linux/iobuf.h>
-#include <linux/highmem.h>
 #include <linux/module.h>
-#include <linux/compiler.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
+#include <linux/writeback.h>
+#include <linux/mempool.h>
+#include <linux/hash.h>
 #include <asm/bitops.h>
-#include <asm/mmu_context.h>
 
-#define MAX_BUF_PER_PAGE (PAGE_CACHE_SIZE / 512)
-#define NR_RESERVED (10*MAX_BUF_PER_PAGE)
-#define MAX_UNUSED_BUFFERS NR_RESERVED+20 /* don't ever have more than this 
-					     number of unused buffer heads */
+#define BH_ENTRY(list) list_entry((list), struct buffer_head, b_inode_buffers)
 
-/* Anti-deadlock ordering:
- *	lru_list_lock > hash_table_lock > unused_list_lock
+/* This is used by some architectures to estimate available memory. */
+atomic_t buffermem_pages = ATOMIC_INIT(0);
+
+/*
+ * Hashed waitqueue_head's for wait_on_buffer()
  */
+#define BH_WAIT_TABLE_ORDER	7
+static struct bh_wait_queue_head {
+	wait_queue_head_t wqh;
+} ____cacheline_aligned_in_smp bh_wait_queue_heads[1<<BH_WAIT_TABLE_ORDER];
 
-#define BH_ENTRY(list) list_entry((list), struct buffer_head, b_inode_buffers)
+/*
+ * Several of these buffer list functions are exported to filesystems,
+ * so we do funny things with the spinlocking to support those
+ * filesystems while still using inode->i_bufferlist_lock for
+ * most applications.
+ * FIXME: put a spinlock in the reiserfs journal and kill this lock.
+ */
+static spinlock_t global_bufferlist_lock = SPIN_LOCK_UNLOCKED;
 
 /*
- * Hash table gook..
+ * Debug/devel support stuff
  */
-static unsigned int bh_hash_mask;
-static unsigned int bh_hash_shift;
-static struct buffer_head **hash_table;
-static rwlock_t hash_table_lock = RW_LOCK_UNLOCKED;
-
-static struct buffer_head *lru_list[NR_LIST];
-static spinlock_t lru_list_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
-static int nr_buffers_type[NR_LIST];
-static unsigned long size_buffers_type[NR_LIST];
-
-static struct buffer_head * unused_list;
-static int nr_unused_buffer_heads;
-static spinlock_t unused_list_lock = SPIN_LOCK_UNLOCKED;
-static DECLARE_WAIT_QUEUE_HEAD(buffer_wait);
 
-static int grow_buffers(struct block_device *bdev, unsigned long block, int size);
-static void __refile_buffer(struct buffer_head *);
+void __buffer_error(char *file, int line)
+{
+	static int enough;
 
-/* This is used by some architectures to estimate available memory. */
-atomic_t buffermem_pages = ATOMIC_INIT(0);
+	if (enough > 10)
+		return;
+	enough++;
+	printk("buffer layer error at %s:%d\n", file, line);
+#ifdef CONFIG_X86
+	printk("Pass this trace through ksymoops for reporting\n");
+	{
+		extern void show_stack(long *esp);
+		show_stack(0);
+	}
+#endif
+}
+EXPORT_SYMBOL(__buffer_error);
+
+inline void
+init_buffer(struct buffer_head *bh, bh_end_io_t *handler, void *private)
+{
+	bh->b_end_io = handler;
+	bh->b_private = private;
+}
+
+/*
+ * Return the address of the waitqueue_head to be used for this
+ * buffer_head
+ */
+static wait_queue_head_t *bh_waitq_head(struct buffer_head *bh)
+{
+	return &bh_wait_queue_heads[hash_ptr(bh, BH_WAIT_TABLE_ORDER)].wqh;
+}
+
+/*
+ * Wait on a buffer until someone does a wakeup on it.  Needs
+ * lots of external locking.  ext3 uses this.  Fix it.
+ */
+void sleep_on_buffer(struct buffer_head *bh)
+{
+	wait_queue_head_t *wq = bh_waitq_head(bh);
+	sleep_on(wq);
+}
+EXPORT_SYMBOL(sleep_on_buffer);
 
-/* Here is the parameter block for the bdflush process. If you add or
- * remove any of the parameters, make sure to update kernel/sysctl.c
- * and the documentation at linux/Documentation/sysctl/vm.txt.
- */
-
-#define N_PARAM 9
-
-/* The dummy values in this structure are left in there for compatibility
- * with old programs that play with the /proc entries.
- */
-union bdflush_param {
-	struct {
-		int nfract;	/* Percentage of buffer cache dirty to 
-				   activate bdflush */
-		int dummy1;	/* old "ndirty" */
-		int dummy2;	/* old "nrefill" */
-		int dummy3;	/* unused */
-		int interval;	/* jiffies delay between kupdate flushes */
-		int age_buffer;	/* Time for normal buffer to age before we flush it */
-		int nfract_sync;/* Percentage of buffer cache dirty to 
-				   activate bdflush synchronously */
-		int dummy4;	/* unused */
-		int dummy5;	/* unused */
-	} b_un;
-	unsigned int data[N_PARAM];
-} bdf_prm = {{40, 0, 0, 0, 5*HZ, 30*HZ, 60, 0, 0}};
-
-/* These are the min and max parameter values that we will allow to be assigned */
-int bdflush_min[N_PARAM] = {  0,  10,    5,   25,  0,   1*HZ,   0, 0, 0};
-int bdflush_max[N_PARAM] = {100,50000, 20000, 20000,10000*HZ, 6000*HZ, 100, 0, 0};
+void wake_up_buffer(struct buffer_head *bh)
+{
+	wait_queue_head_t *wq = bh_waitq_head(bh);
+
+	if (waitqueue_active(wq))
+		wake_up_all(wq);
+}
+EXPORT_SYMBOL(wake_up_buffer);
 
 void unlock_buffer(struct buffer_head *bh)
 {
-	clear_bit(BH_Wait_IO, &bh->b_state);
-	clear_bit(BH_launder, &bh->b_state);
-	clear_bit(BH_Lock, &bh->b_state);
+	/*
+	 * unlock_buffer against a zero-count bh is a bug, if the page
+	 * is not locked.  Because then nothing protects the buffer's
+	 * waitqueue, which is used here. (Well.  Other locked buffers
+	 * against the page will pin it.  But complain anyway).
+	 */
+	if (atomic_read(&bh->b_count) == 0 &&
+			!PageLocked(bh->b_page) &&
+			!PageWriteback(bh->b_page))
+		buffer_error();
+
+	clear_buffer_locked(bh);
 	smp_mb__after_clear_bit();
-	if (waitqueue_active(&bh->b_wait))
-		wake_up(&bh->b_wait);
+	wake_up_buffer(bh);
 }
 
 /*
- * Rewrote the wait-routines to use the "new" wait-queue functionality,
- * and getting rid of the cli-sti pairs. The wait-queue routines still
- * need cli-sti, but now it's just a couple of 386 instructions or so.
- *
- * Note that the real wait_on_buffer() is an inline function that checks
- * if 'b_wait' is set before calling this, so that the queues aren't set
- * up unnecessarily.
+ * Block until a buffer comes unlocked.  This doesn't stop it
+ * from becoming locked again - you have to lock it yourself
+ * if you want to preserve its state.
  */
 void __wait_on_buffer(struct buffer_head * bh)
 {
+	wait_queue_head_t *wq = bh_waitq_head(bh);
 	struct task_struct *tsk = current;
 	DECLARE_WAITQUEUE(wait, tsk);
 
 	get_bh(bh);
-	add_wait_queue(&bh->b_wait, &wait);
+	add_wait_queue(wq, &wait);
 	do {
 		run_task_queue(&tq_disk);
 		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
@@ -153,213 +154,115 @@
 		schedule();
 	} while (buffer_locked(bh));
 	tsk->state = TASK_RUNNING;
-	remove_wait_queue(&bh->b_wait, &wait);
+	remove_wait_queue(wq, &wait);
 	put_bh(bh);
 }
 
-/*
- * Default synchronous end-of-IO handler..  Just mark it up-to-date and
- * unlock the buffer. This is what ll_rw_block uses too.
- */
-void end_buffer_io_sync(struct buffer_head *bh, int uptodate)
+static inline void
+__set_page_buffers(struct page *page, struct buffer_head *head)
 {
-	mark_buffer_uptodate(bh, uptodate);
-	unlock_buffer(bh);
-	put_bh(bh);
-}
+	struct inode *inode = page->mapping->host;
 
-/*
- * The buffers have been marked clean and locked.  Just submit the dang
- * things.. 
- */
-static void write_locked_buffers(struct buffer_head **array, unsigned int count)
-{
-	do {
-		struct buffer_head * bh = *array++;
-		bh->b_end_io = end_buffer_io_sync;
-		submit_bh(WRITE, bh);
-	} while (--count);
+	if (inode && S_ISBLK(inode->i_mode))
+		atomic_inc(&buffermem_pages);
+	if (page_has_buffers(page))
+		buffer_error();
+	set_page_buffers(page, head);
+	page_cache_get(page);
 }
 
-/*
- * Write some buffers from the head of the dirty queue.
- *
- * This must be called with the LRU lock held, and will
- * return without it!
- */
-#define NRSYNC (32)
-static int write_some_buffers(struct block_device *bdev)
+static inline void
+__clear_page_buffers(struct page *page)
 {
-	struct buffer_head *next;
-	struct buffer_head *array[NRSYNC];
-	unsigned int count;
-	int nr;
-
-	next = lru_list[BUF_DIRTY];
-	nr = nr_buffers_type[BUF_DIRTY];
-	count = 0;
-	while (next && --nr >= 0) {
-		struct buffer_head * bh = next;
-		next = bh->b_next_free;
+	struct address_space *mapping = page->mapping;
 
-		if (bdev && bh->b_bdev != bdev)
-			continue;
-		if (test_and_set_bit(BH_Lock, &bh->b_state))
-			continue;
-		if (atomic_set_buffer_clean(bh)) {
-			__refile_buffer(bh);
-			get_bh(bh);
-			array[count++] = bh;
-			if (count < NRSYNC)
-				continue;
+	if (mapping) {
+		struct inode *inode = mapping->host;
 
-			spin_unlock(&lru_list_lock);
-			write_locked_buffers(array, count);
-			return -EAGAIN;
-		}
-		unlock_buffer(bh);
-		__refile_buffer(bh);
+		if (S_ISBLK(inode->i_mode))
+			atomic_dec(&buffermem_pages);
 	}
-	spin_unlock(&lru_list_lock);
-
-	if (count)
-		write_locked_buffers(array, count);
-	return 0;
+	clear_page_buffers(page);
+	page_cache_release(page);
 }
 
 /*
- * Write out all buffers on the dirty list.
+ * Default synchronous end-of-IO handler..  Just mark it up-to-date and
+ * unlock the buffer. This is what ll_rw_block uses too.
  */
-static void write_unlocked_buffers(struct block_device *bdev)
+void end_buffer_io_sync(struct buffer_head *bh, int uptodate)
 {
-	do {
-		spin_lock(&lru_list_lock);
-	} while (write_some_buffers(bdev));
-	run_task_queue(&tq_disk);
+	if (!uptodate)
+		printk("%s: I/O error\n", __FUNCTION__);
+	if (uptodate)
+		set_buffer_uptodate(bh);
+	else
+		clear_buffer_uptodate(bh);
+	unlock_buffer(bh);
+	put_bh(bh);
 }
 
 /*
- * Wait for a buffer on the proper list.
- *
- * This must be called with the LRU lock held, and
- * will return with it released.
+ * Write out and wait upon all the dirty data associated with a block
+ * device via its mapping.  Does not take the superblock lock.
  */
-static int wait_for_buffers(struct block_device *bdev, int index, int refile)
+int sync_blockdev(struct block_device *bdev)
 {
-	struct buffer_head * next;
-	int nr;
-
-	next = lru_list[index];
-	nr = nr_buffers_type[index];
-	while (next && --nr >= 0) {
-		struct buffer_head *bh = next;
-		next = bh->b_next_free;
+	int ret = 0;
 
-		if (!buffer_locked(bh)) {
-			if (refile)
-				__refile_buffer(bh);
-			continue;
-		}
-		if (bdev && bh->b_bdev !=  bdev)
-			continue;
+	if (bdev) {
+		int err;
 
-		get_bh(bh);
-		spin_unlock(&lru_list_lock);
-		wait_on_buffer (bh);
-		put_bh(bh);
-		return -EAGAIN;
+		ret = filemap_fdatawait(bdev->bd_inode->i_mapping);
+		err = filemap_fdatawrite(bdev->bd_inode->i_mapping);
+		if (!ret)
+			ret = err;
+		err = filemap_fdatawait(bdev->bd_inode->i_mapping);
+		if (!ret)
+			ret = err;
 	}
-	spin_unlock(&lru_list_lock);
-	return 0;
-}
-
-static inline void wait_for_some_buffers(struct block_device *bdev)
-{
-	spin_lock(&lru_list_lock);
-	wait_for_buffers(bdev, BUF_LOCKED, 1);
-}
-
-static int wait_for_locked_buffers(struct block_device *bdev, int index, int refile)
-{
-	do {
-		spin_lock(&lru_list_lock);
-	} while (wait_for_buffers(bdev, index, refile));
-	return 0;
+	return ret;
 }
+EXPORT_SYMBOL(sync_blockdev);
 
-/* Call sync_buffers with wait!=0 to ensure that the call does not
- * return until all buffer writes have completed.  Sync() may return
- * before the writes have finished; fsync() may not.
- */
-
-/* Godamity-damn.  Some buffers (bitmaps for filesystems)
- * spontaneously dirty themselves without ever brelse being called.
- * We will ultimately want to put these in a separate list, but for
- * now we search all of the lists for dirty buffers.
+/*
+ * Write out and wait upon all dirty data associated with this
+ * superblock.  Filesystem data as well as the underlying block
+ * device.  Takes the superblock lock.
  */
-int sync_buffers(struct block_device *bdev, int wait)
-{
-	int err = 0;
-
-	if (!bdev)
-		return 0;
-
-	/* One pass for no-wait, three for wait:
-	 * 0) write out all dirty, unlocked buffers;
-	 * 1) wait for all dirty locked buffers;
-	 * 2) write out all dirty, unlocked buffers;
-	 * 2) wait for completion by waiting for all buffers to unlock.
-	 */
-	write_unlocked_buffers(bdev);
-	if (wait) {
-		err = wait_for_locked_buffers(bdev, BUF_DIRTY, 0);
-		write_unlocked_buffers(bdev);
-		err |= wait_for_locked_buffers(bdev, BUF_LOCKED, 1);
-	}
-	return err;
-}
-
-int sync_all_buffers(int wait)
-{
-	int err = 0;
-
-	/* One pass for no-wait, three for wait:
-	 * 0) write out all dirty, unlocked buffers;
-	 * 1) wait for all dirty locked buffers;
-	 * 2) write out all dirty, unlocked buffers;
-	 * 2) wait for completion by waiting for all buffers to unlock.
-	 */
-	write_unlocked_buffers(NULL);
-	if (wait) {
-		err = wait_for_locked_buffers(NULL, BUF_DIRTY, 0);
-		write_unlocked_buffers(NULL);
-		err |= wait_for_locked_buffers(NULL, BUF_LOCKED, 1);
-	}
-	return err;
-}
-
 int fsync_super(struct super_block *sb)
 {
-	sync_buffers(sb->s_bdev, 0);
-
-	lock_kernel();
-	sync_inodes_sb(sb);
+	sync_inodes_sb(sb);	/* All the inodes */
 	DQUOT_SYNC(sb);
 	lock_super(sb);
 	if (sb->s_dirt && sb->s_op && sb->s_op->write_super)
 		sb->s_op->write_super(sb);
 	unlock_super(sb);
-	unlock_kernel();
 
-	return sync_buffers(sb->s_bdev, 1);
+	return sync_blockdev(sb->s_bdev);
 }
 
-int fsync_no_super(struct block_device *bdev)
+/*
+ * Write out and wait upon all dirty data associated with this
+ * device.   Filesystem data as well as the underlying block
+ * device.  Takes the superblock lock.
+ */
+int fsync_bdev(struct block_device *bdev)
 {
-	sync_buffers(bdev, 0);
-	return sync_buffers(bdev, 1);
+	struct super_block *sb = get_super(to_kdev_t(bdev->bd_dev));
+	if (sb) {
+		int res = fsync_super(sb);
+		drop_super(sb);
+		return res;
+	}
+	return sync_blockdev(bdev);
 }
 
+/*
+ * Write out and wait upon all dirty data associated with this
+ * kdev_t.   Filesystem data as well as the underlying block
+ * device.  Takes the superblock lock.
+ */
 int fsync_dev(kdev_t dev)
 {
 	struct block_device *bdev = bdget(kdev_t_to_nr(dev));
@@ -371,33 +274,22 @@
 	return 0;
 }
 
-int fsync_bdev(struct block_device *bdev)
-{
-	struct super_block *sb = get_super(to_kdev_t(bdev->bd_dev));
-	if (sb) {
-		int res = fsync_super(sb);
-		drop_super(sb);
-		return res;
-	}
-	return fsync_no_super(bdev);
-}
-
+/*
+ * sync everything.
+ */
 asmlinkage long sys_sync(void)
 {
-	sync_all_buffers(0);
-
-	lock_kernel();
-	sync_inodes();
+	sync_inodes();	/* All mappings and inodes, including block devices */
 	DQUOT_SYNC(NULL);
-	sync_supers();
-	unlock_kernel();
-
-	sync_all_buffers(1);
+	sync_supers();	/* Write the superblocks */
+	sync_inodes();	/* All the mappings and inodes, again. */
 	return 0;
 }
 
 /*
- *	filp may be NULL if called via the msync of a vma.
+ * Generic function to fsync a file.
+ *
+ * filp may be NULL if called via the msync of a vma.
  */
  
 int file_fsync(struct file *filp, struct dentry *dentry, int datasync)
@@ -406,7 +298,6 @@
 	struct super_block * sb;
 	int ret;
 
-	lock_kernel();
 	/* sync the inode to buffers */
 	write_inode_now(inode, 0);
 
@@ -418,8 +309,7 @@
 	unlock_super(sb);
 
 	/* .. finally sync the buffers to disk */
-	ret = sync_buffers(sb->s_bdev, 1);
-	unlock_kernel();
+	ret = sync_blockdev(sb->s_bdev);
 	return ret;
 }
 
@@ -440,18 +330,21 @@
 
 	ret = -EINVAL;
 	if (!file->f_op || !file->f_op->fsync) {
-		/* Why?  We can still call filemap_fdatasync */
+		/* Why?  We can still call filemap_fdatawrite */
 		goto out_putf;
 	}
 
 	/* We need to protect against concurrent writers.. */
 	down(&inode->i_sem);
-	ret = filemap_fdatasync(inode->i_mapping);
+	ret = filemap_fdatawait(inode->i_mapping);
+	err = filemap_fdatawrite(inode->i_mapping);
+	if (!ret)
+		ret = err;
 	err = file->f_op->fsync(file, dentry, 0);
-	if (err && !ret)
+	if (!ret)
 		ret = err;
 	err = filemap_fdatawait(inode->i_mapping);
-	if (err && !ret)
+	if (!ret)
 		ret = err;
 	up(&inode->i_sem);
 
@@ -481,12 +374,15 @@
 		goto out_putf;
 
 	down(&inode->i_sem);
-	ret = filemap_fdatasync(inode->i_mapping);
+	ret = filemap_fdatawait(inode->i_mapping);
+	err = filemap_fdatawrite(inode->i_mapping);
+	if (!ret)
+		ret = err;
 	err = file->f_op->fsync(file, dentry, 1);
-	if (err && !ret)
+	if (!ret)
 		ret = err;
 	err = filemap_fdatawait(inode->i_mapping);
-	if (err && !ret)
+	if (!ret)
 		ret = err;
 	up(&inode->i_sem);
 
@@ -496,151 +392,94 @@
 	return ret;
 }
 
-/* After several hours of tedious analysis, the following hash
- * function won.  Do not mess with it... -DaveM
+/*
+ * Various filesystems appear to want __get_hash_table to be non-blocking.
+ * But it's the page lock which protects the buffers.  To get around this,
+ * we get exclusion from try_to_free_buffers with the inode's
+ * i_bufferlist_lock.
+ *
+ * Hack idea: for the blockdev mapping, i_bufferlist_lock contention
+ * may be quite high.  This code could TryLock the page, and if that
+ * succeeds, there is no need to take i_bufferlist_lock. (But if
+ * i_bufferlist_lock is contended then so is mapping->page_lock).
  */
-#define _hashfn(dev,block)	\
-	((((dev)<<(bh_hash_shift - 6)) ^ ((dev)<<(bh_hash_shift - 9))) ^ \
-	 (((block)<<(bh_hash_shift - 6)) ^ ((block) >> 13) ^ \
-	  ((block) << (bh_hash_shift - 12))))
-#define hash(dev,block) hash_table[(_hashfn(HASHDEV(dev),block) & bh_hash_mask)]
-
-static inline void __insert_into_hash_list(struct buffer_head *bh)
-{
-	struct buffer_head **head = &hash(to_kdev_t(bh->b_bdev->bd_dev), bh->b_blocknr);
-	struct buffer_head *next = *head;
-
-	*head = bh;
-	bh->b_pprev = head;
-	bh->b_next = next;
-	if (next != NULL)
-		next->b_pprev = &bh->b_next;
-}
-
-static __inline__ void __hash_unlink(struct buffer_head *bh)
-{
-	struct buffer_head **pprev = bh->b_pprev;
-	if (pprev) {
-		struct buffer_head *next = bh->b_next;
-		if (next)
-			next->b_pprev = pprev;
-		*pprev = next;
-		bh->b_pprev = NULL;
-	}
-}
-
-static void __insert_into_lru_list(struct buffer_head * bh, int blist)
+struct buffer_head *
+__get_hash_table(struct block_device *bdev, sector_t block, int unused)
 {
-	struct buffer_head **bhp = &lru_list[blist];
-
-	if (bh->b_prev_free || bh->b_next_free) BUG();
-
-	if(!*bhp) {
-		*bhp = bh;
-		bh->b_prev_free = bh;
-	}
-	bh->b_next_free = *bhp;
-	bh->b_prev_free = (*bhp)->b_prev_free;
-	(*bhp)->b_prev_free->b_next_free = bh;
-	(*bhp)->b_prev_free = bh;
-	nr_buffers_type[blist]++;
-	size_buffers_type[blist] += bh->b_size;
-}
+	struct inode * const inode = bdev->bd_inode;
+	struct buffer_head *ret = NULL;
+	unsigned long index;
+	struct buffer_head *bh;
+	struct buffer_head *head;
+	struct page *page;
 
-static void __remove_from_lru_list(struct buffer_head * bh)
-{
-	struct buffer_head *next = bh->b_next_free;
-	if (next) {
-		struct buffer_head *prev = bh->b_prev_free;
-		int blist = bh->b_list;
+	index = block >> (PAGE_CACHE_SHIFT - inode->i_blkbits);
+	page = find_get_page(inode->i_mapping, index);
+	if (!page)
+		goto out;
 
-		prev->b_next_free = next;
-		next->b_prev_free = prev;
-		if (lru_list[blist] == bh) {
-			if (next == bh)
-				next = NULL;
-			lru_list[blist] = next;
+	spin_lock(&inode->i_bufferlist_lock);
+	if (!page_has_buffers(page))
+		goto out_unlock;
+	head = page_buffers(page);
+	bh = head;
+	do {
+		if (bh->b_blocknr == block) {
+			ret = bh;
+			get_bh(bh);
+			goto out_unlock;
 		}
-		bh->b_next_free = NULL;
-		bh->b_prev_free = NULL;
-		nr_buffers_type[blist]--;
-		size_buffers_type[blist] -= bh->b_size;
-	}
-}
-
-/* must be called with both the hash_table_lock and the lru_list_lock
-   held */
-static void __remove_from_queues(struct buffer_head *bh)
-{
-	__hash_unlink(bh);
-	__remove_from_lru_list(bh);
-}
-
-static void remove_from_queues(struct buffer_head *bh)
-{
-	spin_lock(&lru_list_lock);
-	write_lock(&hash_table_lock);
-	__remove_from_queues(bh);
-	write_unlock(&hash_table_lock);	
-	spin_unlock(&lru_list_lock);
+		bh = bh->b_this_page;
+	} while (bh != head);
+	buffer_error();
+out_unlock:
+	spin_unlock(&inode->i_bufferlist_lock);
+	page_cache_release(page);
+out:
+	return ret;
 }
 
-struct buffer_head * __get_hash_table(struct block_device *bdev, sector_t block, int size)
+struct buffer_head *get_hash_table(kdev_t dev, sector_t block, int size)
 {
-	struct buffer_head *bh, **p = &hash(to_kdev_t(bdev->bd_dev), block);
-
-	read_lock(&hash_table_lock);
-
-	for (;;) {
-		bh = *p;
-		if (!bh)
-			break;
-		p = &bh->b_next;
-		if (bh->b_blocknr != block)
-			continue;
-		if (bh->b_size != size)
-			continue;
-		if (bh->b_bdev != bdev)
-			continue;
-		get_bh(bh);
-		break;
+	struct block_device *bdev;
+	struct buffer_head *bh;
+	bdev = bdget(kdev_t_to_nr(dev));
+	if (!bdev) {
+		printk("No block device for %s\n", __bdevname(dev));
+		BUG();
 	}
-
-	read_unlock(&hash_table_lock);
+	bh = __get_hash_table(bdev, block, size);
+	atomic_dec(&bdev->bd_count);
 	return bh;
 }
+EXPORT_SYMBOL(get_hash_table);
 
-void buffer_insert_list(struct buffer_head *bh, struct list_head *list)
-{
-	spin_lock(&lru_list_lock);
-	if (bh->b_inode)
-		list_del(&bh->b_inode_buffers);
-	bh->b_inode = 1;
-	list_add(&bh->b_inode_buffers, list);
-	spin_unlock(&lru_list_lock);
-}
-
-/* The caller must have the lru_list lock before calling the 
-   remove_inode_queue functions.  */
-static void __remove_inode_queue(struct buffer_head *bh)
+void buffer_insert_list(spinlock_t *lock,
+		struct buffer_head *bh, struct list_head *list)
 {
-	bh->b_inode = 0;
+	if (lock == NULL)
+		lock = &global_bufferlist_lock;
+	spin_lock(lock);
 	list_del(&bh->b_inode_buffers);
+	list_add(&bh->b_inode_buffers, list);
+	spin_unlock(lock);
 }
 
-static inline void remove_inode_queue(struct buffer_head *bh)
+/*
+ * i_bufferlist_lock must be held
+ */
+static inline void __remove_inode_queue(struct buffer_head *bh)
 {
-	if (bh->b_inode)
-		__remove_inode_queue(bh);
+	list_del_init(&bh->b_inode_buffers);
 }
 
 int inode_has_buffers(struct inode *inode)
 {
 	int ret;
 	
-	spin_lock(&lru_list_lock);
-	ret = !list_empty(&inode->i_dirty_buffers) || !list_empty(&inode->i_dirty_data_buffers);
-	spin_unlock(&lru_list_lock);
+	spin_lock(&inode->i_bufferlist_lock);
+	ret = !list_empty(&inode->i_dirty_buffers);
+	spin_unlock(&inode->i_bufferlist_lock);
 	
 	return ret;
 }
@@ -679,58 +518,11 @@
    pass does the actual I/O. */
 void invalidate_bdev(struct block_device *bdev, int destroy_dirty_buffers)
 {
-	int i, nlist, slept;
-	struct buffer_head * bh, * bh_next;
-
- retry:
-	slept = 0;
-	spin_lock(&lru_list_lock);
-	for(nlist = 0; nlist < NR_LIST; nlist++) {
-		bh = lru_list[nlist];
-		if (!bh)
-			continue;
-		for (i = nr_buffers_type[nlist]; i > 0 ; bh = bh_next, i--) {
-			bh_next = bh->b_next_free;
-
-			/* Another device? */
-			if (bh->b_bdev != bdev)
-				continue;
-			/* Not hashed? */
-			if (!bh->b_pprev)
-				continue;
-			if (buffer_locked(bh)) {
-				get_bh(bh);
-				spin_unlock(&lru_list_lock);
-				wait_on_buffer(bh);
-				slept = 1;
-				spin_lock(&lru_list_lock);
-				put_bh(bh);
-			}
-
-			write_lock(&hash_table_lock);
-			/* All buffers in the lru lists are mapped */
-			if (!buffer_mapped(bh))
-				BUG();
-			if (buffer_dirty(bh))
-				printk("invalidate: dirty buffer\n");
-			if (!atomic_read(&bh->b_count)) {
-				if (destroy_dirty_buffers || !buffer_dirty(bh)) {
-					remove_inode_queue(bh);
-				}
-			} else
-				printk("invalidate: busy buffer\n");
-
-			write_unlock(&hash_table_lock);
-			if (slept)
-				goto out;
-		}
-	}
-out:
-	spin_unlock(&lru_list_lock);
-	if (slept)
-		goto retry;
-
-	/* Get rid of the page cache */
+	/*
+	 * FIXME: what about destroy_dirty_buffers?
+	 * We really want to use invalidate_inode_pages2() for
+	 * that, but not until that's cleaned up.
+	 */
 	invalidate_inode_pages(bdev->bd_inode);
 }
 
@@ -743,11 +535,16 @@
 	}
 }
 
+/*
+ * FIXME: What is this function actually trying to do?  Why "zones[0]"?
+ * Is it still correct/needed if/when blockdev mappings use GFP_HIGHUSER?
+ */
 static void free_more_memory(void)
 {
-	zone_t * zone = contig_page_data.node_zonelists[GFP_NOFS & GFP_ZONEMASK].zones[0];
-	
-	balance_dirty();
+	zone_t *zone;
+
+	zone = contig_page_data.node_zonelists[GFP_NOFS & GFP_ZONEMASK].zones[0];
+
 	wakeup_bdflush();
 	try_to_free_pages(zone, GFP_NOFS, 0);
 	run_task_queue(&tq_disk);
@@ -755,25 +552,22 @@
 	yield();
 }
 
-void init_buffer(struct buffer_head *bh, bh_end_io_t *handler, void *private)
-{
-	bh->b_list = BUF_CLEAN;
-	bh->b_end_io = handler;
-	bh->b_private = private;
-}
-
-static void end_buffer_io_async(struct buffer_head * bh, int uptodate)
+static void end_buffer_io_async(struct buffer_head *bh, int uptodate)
 {
 	static spinlock_t page_uptodate_lock = SPIN_LOCK_UNLOCKED;
 	unsigned long flags;
 	struct buffer_head *tmp;
 	struct page *page;
+	int page_uptodate = 1;
 
-	mark_buffer_uptodate(bh, uptodate);
+	if (!uptodate)
+		printk("%s: I/O error\n", __FUNCTION__);
 
-	/* This is a temporary buffer used for page I/O. */
+	if (uptodate)
+		set_buffer_uptodate(bh);
+	else
+		clear_buffer_uptodate(bh);
 	page = bh->b_page;
-
 	if (!uptodate)
 		SetPageError(page);
 
@@ -781,39 +575,37 @@
 	 * Be _very_ careful from here on. Bad things can happen if
 	 * two buffer heads end IO at almost the same time and both
 	 * decide that the page is now completely done.
-	 *
-	 * Async buffer_heads are here only as labels for IO, and get
-	 * thrown away once the IO for this page is complete.  IO is
-	 * deemed complete once all buffers have been visited
-	 * (b_count==0) and are now unlocked. We must make sure that
-	 * only the _last_ buffer that decrements its count is the one
-	 * that unlock the page..
 	 */
 	spin_lock_irqsave(&page_uptodate_lock, flags);
-	mark_buffer_async(bh, 0);
+	clear_buffer_async(bh);
 	unlock_buffer(bh);
-	tmp = bh->b_this_page;
-	while (tmp != bh) {
-		if (buffer_locked(tmp)) {
-			if (buffer_async(tmp))
+	tmp = bh;
+	do {
+		if (!buffer_uptodate(tmp))
+			page_uptodate = 0;
+		if (buffer_async(tmp)) {
+			if (buffer_locked(tmp))
 				goto still_busy;
-		} else if (!buffer_uptodate(tmp))
-			SetPageError(page);
+			if (!buffer_mapped(bh))
+				BUG();
+		}
 		tmp = tmp->b_this_page;
-	}
-
-	/* OK, the async IO on this page is complete. */
+	} while (tmp != bh);
 	spin_unlock_irqrestore(&page_uptodate_lock, flags);
 
 	/*
-	 * if none of the buffers had errors then we can set the
-	 * page uptodate:
+	 * If none of the buffers had errors and they are all
+	 * uptodate then we can set the page uptodate.
 	 */
-	if (!PageError(page))
+	if (page_uptodate && !PageError(page))
 		SetPageUptodate(page);
-
-	UnlockPage(page);
-
+	if (PageWriteback(page)) {
+		/* It was a write */
+		end_page_writeback(page);
+	} else {
+		/* read */
+		unlock_page(page);
+	}
 	return;
 
 still_busy:
@@ -821,10 +613,65 @@
 	return;
 }
 
+/*
+ * If a page's buffers are under async writeout (end_buffer_io_async
+ * completion) then there is a possibility that another thread of
+ * control could lock one of the buffers after it has completed
+ * but while some of the other buffers have not completed.  This
+ * locked buffer would confuse end_buffer_io_async() into not unlocking
+ * the page.  So the absence of BH_Async tells end_buffer_io_async()
+ * that this buffer is not under async I/O.
+ *
+ * The page comes unlocked when it has no locked buffer_async buffers
+ * left.
+ *
+ * The page lock prevents anyone starting new async I/O against any of
+ * the buffers.
+ */
 inline void set_buffer_async_io(struct buffer_head *bh)
 {
 	bh->b_end_io = end_buffer_io_async;
-	mark_buffer_async(bh, 1);
+	set_buffer_async(bh);
+}
+EXPORT_SYMBOL(set_buffer_async_io);
+
+/*
+ * osync is designed to support O_SYNC io.  It waits synchronously for
+ * all already-submitted IO to complete, but does not queue any new
+ * writes to the disk.
+ *
+ * To do O_SYNC writes, just queue the buffer writes with ll_rw_block as
+ * you dirty the buffers, and then use osync_inode_buffers to wait for
+ * completion.  Any other dirty buffers which are not yet queued for
+ * write will not be flushed to disk by the osync.
+ */
+static int osync_buffers_list(spinlock_t *lock, struct list_head *list)
+{
+	struct buffer_head *bh;
+	struct list_head *p;
+	int err = 0;
+
+	if (lock == NULL)
+		lock = &global_bufferlist_lock;
+
+	spin_lock(lock);
+repeat:
+	for (p = list->prev; 
+	     bh = BH_ENTRY(p), p != list;
+	     p = bh->b_inode_buffers.prev) {
+		if (buffer_locked(bh)) {
+			get_bh(bh);
+			spin_unlock(lock);
+			wait_on_buffer(bh);
+			if (!buffer_uptodate(bh))
+				err = -EIO;
+			brelse(bh);
+			spin_lock(lock);
+			goto repeat;
+		}
+	}
+	spin_unlock(lock);
+	return err;
 }
 
 /*
@@ -846,50 +693,47 @@
  * the osync code to catch these locked, dirty buffers without requeuing
  * any newly dirty buffers for write.
  */
-
-int fsync_buffers_list(struct list_head *list)
+int fsync_buffers_list(spinlock_t *lock, struct list_head *list)
 {
 	struct buffer_head *bh;
 	struct list_head tmp;
 	int err = 0, err2;
+
+	if (lock == NULL)
+		lock = &global_bufferlist_lock;
 	
 	INIT_LIST_HEAD(&tmp);
-	
-	spin_lock(&lru_list_lock);
 
+	spin_lock(lock);
 	while (!list_empty(list)) {
 		bh = BH_ENTRY(list->next);
-		list_del(&bh->b_inode_buffers);
-		if (!buffer_dirty(bh) && !buffer_locked(bh))
-			bh->b_inode = 0;
-		else {
-			bh->b_inode = 1;
+		list_del_init(&bh->b_inode_buffers);
+		if (buffer_dirty(bh) || buffer_locked(bh)) {
 			list_add(&bh->b_inode_buffers, &tmp);
 			if (buffer_dirty(bh)) {
 				get_bh(bh);
-				spin_unlock(&lru_list_lock);
+				spin_unlock(lock);
 				ll_rw_block(WRITE, 1, &bh);
 				brelse(bh);
-				spin_lock(&lru_list_lock);
+				spin_lock(lock);
 			}
 		}
 	}
 
 	while (!list_empty(&tmp)) {
 		bh = BH_ENTRY(tmp.prev);
-		remove_inode_queue(bh);
+		__remove_inode_queue(bh);
 		get_bh(bh);
-		spin_unlock(&lru_list_lock);
+		spin_unlock(lock);
 		wait_on_buffer(bh);
 		if (!buffer_uptodate(bh))
 			err = -EIO;
 		brelse(bh);
-		spin_lock(&lru_list_lock);
+		spin_lock(lock);
 	}
 	
-	spin_unlock(&lru_list_lock);
-	err2 = osync_buffers_list(list);
-
+	spin_unlock(lock);
+	err2 = osync_buffers_list(lock, list);
 	if (err)
 		return err;
 	else
@@ -897,46 +741,6 @@
 }
 
 /*
- * osync is designed to support O_SYNC io.  It waits synchronously for
- * all already-submitted IO to complete, but does not queue any new
- * writes to the disk.
- *
- * To do O_SYNC writes, just queue the buffer writes with ll_rw_block as
- * you dirty the buffers, and then use osync_inode_buffers to wait for
- * completion.  Any other dirty buffers which are not yet queued for
- * write will not be flushed to disk by the osync.
- */
-
-int osync_buffers_list(struct list_head *list)
-{
-	struct buffer_head *bh;
-	struct list_head *p;
-	int err = 0;
-
-	spin_lock(&lru_list_lock);
-	
- repeat:
-	
-	for (p = list->prev; 
-	     bh = BH_ENTRY(p), p != list;
-	     p = bh->b_inode_buffers.prev) {
-		if (buffer_locked(bh)) {
-			get_bh(bh);
-			spin_unlock(&lru_list_lock);
-			wait_on_buffer(bh);
-			if (!buffer_uptodate(bh))
-				err = -EIO;
-			brelse(bh);
-			spin_lock(&lru_list_lock);
-			goto repeat;
-		}
-	}
-
-	spin_unlock(&lru_list_lock);
-	return err;
-}
-
-/*
  * Invalidate any and all dirty buffers on a given inode.  We are
  * probably unmounting the fs, but that doesn't mean we have already
  * done a sync().  Just drop the buffers from the inode list.
@@ -945,150 +749,306 @@
 {
 	struct list_head * entry;
 	
-	spin_lock(&lru_list_lock);
-	while ((entry = inode->i_dirty_buffers.next) != &inode->i_dirty_buffers)
-		remove_inode_queue(BH_ENTRY(entry));
-	while ((entry = inode->i_dirty_data_buffers.next) != &inode->i_dirty_data_buffers)
-		remove_inode_queue(BH_ENTRY(entry));
-	spin_unlock(&lru_list_lock);
+	spin_lock(&inode->i_bufferlist_lock);
+	while ((entry = inode->i_dirty_buffers.next) !=
+				&inode->i_dirty_buffers)
+		__remove_inode_queue(BH_ENTRY(entry));
+	spin_unlock(&inode->i_bufferlist_lock);
 }
 
-
 /*
- * Ok, this is getblk, and it isn't very clear, again to hinder
- * race-conditions. Most of the code is seldom used, (ie repeating),
- * so it should be much more efficient than it looks.
- *
- * The algorithm is changed: hopefully better, and an elusive bug removed.
- *
- * 14.02.92: changed it to sync dirty buffers a bit: better performance
- * when the filesystem starts to get full of dirty blocks (I hope).
+ * Create the appropriate buffers when given a page for data area and
+ * the size of each buffer.. Use the bh->b_this_page linked list to
+ * follow the buffers created.  Return NULL if unable to create more
+ * buffers.
+ * The async flag is used to differentiate async IO (paging, swapping)
+ * from ordinary buffer allocations, and only async requests are allowed
+ * to sleep waiting for buffer heads. 
  */
-struct buffer_head * __getblk(struct block_device *bdev, sector_t block, int size)
+static struct buffer_head *
+create_buffers(struct page * page, unsigned long size, int async)
 {
-	for (;;) {
-		struct buffer_head * bh;
+	struct buffer_head *bh, *head;
+	long offset;
 
-		bh = __get_hash_table(bdev, block, size);
-		if (bh)
-			return bh;
+try_again:
+	head = NULL;
+	offset = PAGE_SIZE;
+	while ((offset -= size) >= 0) {
+		bh = alloc_buffer_head(async);
+		if (!bh)
+			goto no_grow;
 
-		if (!grow_buffers(bdev, block, size))
-			free_more_memory();
+		bh->b_bdev = NULL;
+		bh->b_this_page = head;
+		head = bh;
+
+		bh->b_state = 0;
+		atomic_set(&bh->b_count, 0);
+		bh->b_size = size;
+
+		/* Link the buffer to its page */
+		set_bh_page(bh, page, offset);
+
+		bh->b_end_io = NULL;
 	}
+	return head;
+/*
+ * In case anything failed, we just free everything we got.
+ */
+no_grow:
+	if (head) {
+		do {
+			bh = head;
+			head = head->b_this_page;
+			free_buffer_head(bh);
+		} while (head);
+	}
+
+	/*
+	 * Return failure for non-async IO requests.  Async IO requests
+	 * are not allowed to fail, so we have to wait until buffer heads
+	 * become available.  But we don't want tasks sleeping with 
+	 * partially complete buffers, so all were released above.
+	 */
+	if (!async)
+		return NULL;
+
+	/* We're _really_ low on memory. Now we just
+	 * wait for old buffer heads to become free due to
+	 * finishing IO.  Since this is an async request and
+	 * the reserve list is empty, we're sure there are 
+	 * async buffer heads in use.
+	 */
+	run_task_queue(&tq_disk);
+
+	free_more_memory();
+	goto try_again;
 }
 
-/* -1 -> no need to flush
-    0 -> async flush
-    1 -> sync flush (wait for I/O completion) */
-static int balance_dirty_state(void)
-{
-	unsigned long dirty, tot, hard_dirty_limit, soft_dirty_limit;
-
-	dirty = (size_buffers_type[BUF_DIRTY] + size_buffers_type[BUF_LOCKED]) >> PAGE_SHIFT;
-	tot = nr_free_buffer_pages();
-
-	dirty *= 100;
-	soft_dirty_limit = tot * bdf_prm.b_un.nfract;
-	hard_dirty_limit = tot * bdf_prm.b_un.nfract_sync;
-
-	/* First, check for the "real" dirty limit. */
-	if (dirty > soft_dirty_limit) {
-		if (dirty > hard_dirty_limit && !(current->flags & PF_NOIO))
-			return 1;
-		return 0;
-	}
+static inline void
+link_dev_buffers(struct page *page, struct buffer_head *head)
+{
+	struct buffer_head *bh, *tail;
+
+	bh = head;
+	do {
+		tail = bh;
+		bh = bh->b_this_page;
+	} while (bh);
+	tail->b_this_page = head;
+	__set_page_buffers(page, head);
+}
 
-	return -1;
+/*
+ * Initialise the state of a blockdev page's buffers.
+ */ 
+static /*inline*/ void
+init_page_buffers(struct page *page, struct block_device *bdev,
+			int block, int size)
+{
+	struct buffer_head *head = page_buffers(page);
+	struct buffer_head *bh = head;
+	unsigned int b_state;
+
+	b_state = 1 << BH_Mapped;
+	if (PageUptodate(page))
+		b_state |= 1 << BH_Uptodate;
+
+	do {
+		if (!(bh->b_state & (1 << BH_Mapped))) {
+			init_buffer(bh, NULL, NULL);
+			bh->b_bdev = bdev;
+			bh->b_blocknr = block;
+			bh->b_state = b_state;
+		}
+		block++;
+		bh = bh->b_this_page;
+	} while (bh != head);
 }
 
 /*
- * if a new dirty buffer is created we need to balance bdflush.
+ * Create the page-cache page that contains the requested block.
  *
- * in the future we might want to make bdflush aware of different
- * pressures on different devices - thus the (currently unused)
- * 'dev' parameter.
+ * This is user purely for blockdev mappings.
  */
-void balance_dirty(void)
+static /*inline*/ struct page *
+grow_dev_page(struct block_device *bdev, unsigned long block,
+			unsigned long index, int size)
 {
-	int state = balance_dirty_state();
+	struct inode *inode = bdev->bd_inode;
+	struct page *page;
+	struct buffer_head *bh;
 
-	if (state < 0)
-		return;
+	page = find_or_create_page(inode->i_mapping, index, GFP_NOFS);
+	if (!page)
+		return NULL;
 
-	/* If we're getting into imbalance, start write-out */
-	spin_lock(&lru_list_lock);
-	write_some_buffers(NULL);
+	if (!PageLocked(page))
+		BUG();
+
+	if (page_has_buffers(page)) {
+		bh = page_buffers(page);
+		if (bh->b_size == size)
+			return page;
+		if (!try_to_free_buffers(page))
+			goto failed;
+	}
 
 	/*
-	 * And if we're _really_ out of balance, wait for
-	 * some of the dirty/locked buffers ourselves and
-	 * start bdflush.
-	 * This will throttle heavy writers.
+	 * Allocate some buffers for this page
 	 */
-	if (state > 0) {
-		wait_for_some_buffers(NULL);
-		wakeup_bdflush();
-	}
-}
+	bh = create_buffers(page, size, 0);
+	if (!bh)
+		goto failed;
 
-inline void __mark_dirty(struct buffer_head *bh)
-{
-	bh->b_flushtime = jiffies + bdf_prm.b_un.age_buffer;
-	refile_buffer(bh);
+	/*
+	 * Link the page to the buffers and initialise them.  Take the
+	 * lock to be atomic wrt __get_hash_table(), which does not
+	 * run under the page lock.
+	 */
+	spin_lock(&inode->i_bufferlist_lock);
+	link_dev_buffers(page, bh);
+	init_page_buffers(page, bdev, block, size);
+	spin_unlock(&inode->i_bufferlist_lock);
+	return page;
+
+failed:
+	buffer_error();
+	unlock_page(page);
+	page_cache_release(page);
+	return NULL;
 }
 
-/* atomic version, the user must call balance_dirty() by hand
-   as soon as it become possible to block */
-void __mark_buffer_dirty(struct buffer_head *bh)
+/*
+ * Create buffers for the specified block device block's page.  If
+ * that page was dirty, the buffers are set dirty also.
+ *
+ * Except that's a bug.  Attaching dirty buffers to a dirty
+ * blockdev's page can result in filesystem corruption, because
+ * some of those buffers may be aliases of filesystem data.
+ * grow_dev_page() will go BUG() if this happens.
+ */
+static inline int
+grow_buffers(struct block_device *bdev, unsigned long block, int size)
 {
-	if (!atomic_set_buffer_dirty(bh))
-		__mark_dirty(bh);
+	struct page *page;
+	unsigned long index;
+	int sizebits;
+
+	/* Size must be multiple of hard sectorsize */
+	if (size & (bdev_hardsect_size(bdev)-1))
+		BUG();
+	if (size < 512 || size > PAGE_SIZE)
+		BUG();
+
+	sizebits = -1;
+	do {
+		sizebits++;
+	} while ((size << sizebits) < PAGE_SIZE);
+
+	index = block >> sizebits;
+	block = index << sizebits;
+
+	/* Create a page with the proper size buffers.. */
+	page = grow_dev_page(bdev, block, index, size);
+	if (!page)
+		return 0;
+	unlock_page(page);
+	page_cache_release(page);
+	return 1;
 }
 
-void mark_buffer_dirty(struct buffer_head *bh)
+/*
+ * __getblk will locate (and, if necessary, create) the buffer_head
+ * which corresponds to the passed block_device, block and size. The
+ * returned buffer has its reference count incremented.
+ *
+ * __getblk() cannot fail - it just keeps trying.  If you pass it an
+ * illegal block number, __getblk() will happily return a buffer_head
+ * which represents the non-existent block.  Very weird.
+ *
+ * __getblk() will lock up the machine if grow_dev_page's try_to_free_buffers()
+ * attempt is failing.  FIXME, perhaps?
+ */
+struct buffer_head *
+__getblk(struct block_device *bdev, sector_t block, int size)
 {
-	if (!atomic_set_buffer_dirty(bh)) {
-		__mark_dirty(bh);
-		balance_dirty();
+	for (;;) {
+		struct buffer_head * bh;
+
+		bh = __get_hash_table(bdev, block, size);
+		if (bh) {
+			touch_buffer(bh);
+			return bh;
+		}
+
+		if (!grow_buffers(bdev, block, size))
+			free_more_memory();
 	}
 }
 
-void set_buffer_flushtime(struct buffer_head *bh)
+struct buffer_head *getblk(kdev_t dev, sector_t block, int size)
 {
-	bh->b_flushtime = jiffies + bdf_prm.b_un.age_buffer;
+	struct block_device *bdev;
+	struct buffer_head *bh;
+	bdev = bdget(kdev_t_to_nr(dev));
+	if (!bdev) {
+		printk("No block device for %s\n", __bdevname(dev));
+		BUG();
+	}
+	bh = __getblk(bdev, block, size);
+	atomic_dec(&bdev->bd_count);
+	return bh;
 }
-EXPORT_SYMBOL(set_buffer_flushtime);
+EXPORT_SYMBOL(getblk);
 
 /*
- * A buffer may need to be moved from one buffer list to another
- * (e.g. in case it is not shared any more). Handle this.
+ * The relationship between dirty buffers and dirty pages:
+ *
+ * Whenever a page has any dirty buffers, the page's dirty bit is set, and
+ * the page appears on its address_space.dirty_pages list.
+ *
+ * At all times, the dirtiness of the buffers represents the dirtiness of
+ * subsections of the page.  If the page has buffers, the page dirty bit is
+ * merely a hint about the true dirty state.
+ *
+ * When a page is set dirty in its entirety, all its buffers are marked dirty
+ * (if the page has buffers).
+ *
+ * When a buffer is marked dirty, its page is dirtied, but the page's other
+ * buffers are not.
+ *
+ * Also.  When blockdev buffers are explicitly read with bread(), they
+ * individually become uptodate.  But their backing page remains not
+ * uptodate - even if all of its buffers are uptodate.  A subsequent
+ * block_read_full_page() against that page will discover all the uptodate
+ * buffers, will set the page uptodate and will perform no I/O.
  */
-static void __refile_buffer(struct buffer_head *bh)
-{
-	int dispose = BUF_CLEAN;
-	if (buffer_locked(bh))
-		dispose = BUF_LOCKED;
-	if (buffer_dirty(bh))
-		dispose = BUF_DIRTY;
-	if (dispose != bh->b_list) {
-		__remove_from_lru_list(bh);
-		bh->b_list = dispose;
-		if (dispose == BUF_CLEAN)
-			remove_inode_queue(bh);
-		__insert_into_lru_list(bh, dispose);
-	}
-}
 
-void refile_buffer(struct buffer_head *bh)
+/**
+ * mark_buffer_dirty - mark a buffer_head as needing writeout
+ *
+ * mark_buffer_dirty() will set the dirty bit against the buffer,
+ * then set its backing page dirty, then attach the page to its
+ * address_space's dirty_pages list and then attach the address_space's
+ * inode to its superblock's dirty inode list.
+ *
+ * mark_buffer_dirty() is atomic.  It takes inode->i_bufferlist_lock,
+ * mapping->page_lock and the global inode_lock.
+ */
+void mark_buffer_dirty(struct buffer_head *bh)
 {
-	spin_lock(&lru_list_lock);
-	__refile_buffer(bh);
-	spin_unlock(&lru_list_lock);
+	if (!test_set_buffer_dirty(bh))
+		__set_page_dirty_nobuffers(bh->b_page);
 }
 
 /*
- * Release a buffer head
+ * Decrement a buffer_head's reference count.  If all buffers against a page
+ * have zero reference count, are clean and unlocked, and if the page is clean
+ * and unlocked then try_to_free_buffers() may strip the buffers from the page
+ * in preparation for freeing it (sometimes, rarely, buffers are removed from
+ * a page but it ends up not being freed, and buffers may later be reattached).
  */
 void __brelse(struct buffer_head * buf)
 {
@@ -1097,6 +1057,7 @@
 		return;
 	}
 	printk(KERN_ERR "VFS: brelse: Trying to free free buffer\n");
+	buffer_error();		/* For the stack backtrace */
 }
 
 /*
@@ -1105,110 +1066,59 @@
  */
 void __bforget(struct buffer_head * buf)
 {
-	mark_buffer_clean(buf);
+	clear_buffer_dirty(buf);
 	__brelse(buf);
 }
 
 /**
- *	bread() - reads a specified block and returns the bh
- *	@block: number of block
- *	@size: size (in bytes) to read
+ *  bread() - reads a specified block and returns the bh
+ *  @block: number of block
+ *  @size: size (in bytes) to read
  * 
- *	Reads a specified block, and returns buffer head that
- *	contains it. It returns NULL if the block was unreadable.
+ *  Reads a specified block, and returns buffer head that contains it.
+ *  It returns NULL if the block was unreadable.
  */
 struct buffer_head * __bread(struct block_device *bdev, int block, int size)
 {
-	struct buffer_head * bh = __getblk(bdev, block, size);
+	struct buffer_head *bh = __getblk(bdev, block, size);
 
-	touch_buffer(bh);
 	if (buffer_uptodate(bh))
 		return bh;
-	ll_rw_block(READ, 1, &bh);
-	wait_on_buffer(bh);
-	if (buffer_uptodate(bh))
+	lock_buffer(bh);
+	if (buffer_uptodate(bh)) {
+		unlock_buffer(bh);
 		return bh;
+	} else {
+		if (buffer_dirty(bh))
+			buffer_error();
+		get_bh(bh);
+		bh->b_end_io = end_buffer_io_sync;
+		submit_bh(READ, bh);
+		wait_on_buffer(bh);
+		if (buffer_uptodate(bh))
+			return bh;
+	}
 	brelse(bh);
 	return NULL;
 }
 
-/*
- * Note: the caller should wake up the buffer_wait list if needed.
- */
-static void __put_unused_buffer_head(struct buffer_head * bh)
+struct buffer_head *bread(kdev_t dev, int block, int size)
 {
-	if (bh->b_inode)
+	struct block_device *bdev;
+	struct buffer_head *bh;
+	bdev = bdget(kdev_t_to_nr(dev));
+	if (!bdev) {
+		printk("No block device for %s\n", __bdevname(dev));
 		BUG();
-	if (nr_unused_buffer_heads >= MAX_UNUSED_BUFFERS) {
-		kmem_cache_free(bh_cachep, bh);
-	} else {
-		bh->b_bdev = NULL;
-		bh->b_blocknr = -1;
-		bh->b_this_page = NULL;
-
-		nr_unused_buffer_heads++;
-		bh->b_next_free = unused_list;
-		unused_list = bh;
 	}
+	bh = __bread(bdev, block, size);
+	atomic_dec(&bdev->bd_count);
+	return bh;
 }
+EXPORT_SYMBOL(bread);
 
-void put_unused_buffer_head(struct buffer_head *bh)
-{
-	spin_lock(&unused_list_lock);
-	__put_unused_buffer_head(bh);
-	spin_unlock(&unused_list_lock);
-}
-EXPORT_SYMBOL(put_unused_buffer_head);
-
-/*
- * Reserve NR_RESERVED buffer heads for async IO requests to avoid
- * no-buffer-head deadlock.  Return NULL on failure; waiting for
- * buffer heads is now handled in create_buffers().
- */ 
-struct buffer_head * get_unused_buffer_head(int async)
-{
-	struct buffer_head * bh;
-
-	spin_lock(&unused_list_lock);
-	if (nr_unused_buffer_heads > NR_RESERVED) {
-		bh = unused_list;
-		unused_list = bh->b_next_free;
-		nr_unused_buffer_heads--;
-		spin_unlock(&unused_list_lock);
-		return bh;
-	}
-	spin_unlock(&unused_list_lock);
-
-	/* This is critical.  We can't call out to the FS
-	 * to get more buffer heads, because the FS may need
-	 * more buffer-heads itself.  Thus SLAB_NOFS.
-	 */
-	if((bh = kmem_cache_alloc(bh_cachep, SLAB_NOFS)) != NULL) {
-		bh->b_blocknr = -1;
-		bh->b_this_page = NULL;
-		return bh;
-	}
-
-	/*
-	 * If we need an async buffer, use the reserved buffer heads.
-	 */
-	if (async) {
-		spin_lock(&unused_list_lock);
-		if (unused_list) {
-			bh = unused_list;
-			unused_list = bh->b_next_free;
-			nr_unused_buffer_heads--;
-			spin_unlock(&unused_list_lock);
-			return bh;
-		}
-		spin_unlock(&unused_list_lock);
-	}
-
-	return NULL;
-}
-EXPORT_SYMBOL(get_unused_buffer_head);
-
-void set_bh_page (struct buffer_head *bh, struct page *page, unsigned long offset)
+void set_bh_page(struct buffer_head *bh,
+		struct page *page, unsigned long offset)
 {
 	bh->b_page = page;
 	if (offset >= PAGE_SIZE)
@@ -1224,124 +1134,67 @@
 EXPORT_SYMBOL(set_bh_page);
 
 /*
- * Create the appropriate buffers when given a page for data area and
- * the size of each buffer.. Use the bh->b_this_page linked list to
- * follow the buffers created.  Return NULL if unable to create more
- * buffers.
- * The async flag is used to differentiate async IO (paging, swapping)
- * from ordinary buffer allocations, and only async requests are allowed
- * to sleep waiting for buffer heads. 
- */
-static struct buffer_head * create_buffers(struct page * page, unsigned long size, int async)
-{
-	struct buffer_head *bh, *head;
-	long offset;
-
-try_again:
-	head = NULL;
-	offset = PAGE_SIZE;
-	while ((offset -= size) >= 0) {
-		bh = get_unused_buffer_head(async);
-		if (!bh)
-			goto no_grow;
-
-		bh->b_bdev = NULL;
-		bh->b_this_page = head;
-		head = bh;
-
-		bh->b_state = 0;
-		bh->b_next_free = NULL;
-		bh->b_pprev = NULL;
-		atomic_set(&bh->b_count, 0);
-		bh->b_size = size;
-
-		set_bh_page(bh, page, offset);
-
-		bh->b_list = BUF_CLEAN;
-		bh->b_end_io = NULL;
-	}
-	return head;
-/*
- * In case anything failed, we just free everything we got.
- */
-no_grow:
-	if (head) {
-		spin_lock(&unused_list_lock);
-		do {
-			bh = head;
-			head = head->b_this_page;
-			__put_unused_buffer_head(bh);
-		} while (head);
-		spin_unlock(&unused_list_lock);
-
-		/* Wake up any waiters ... */
-		wake_up(&buffer_wait);
-	}
-
-	/*
-	 * Return failure for non-async IO requests.  Async IO requests
-	 * are not allowed to fail, so we have to wait until buffer heads
-	 * become available.  But we don't want tasks sleeping with 
-	 * partially complete buffers, so all were released above.
-	 */
-	if (!async)
-		return NULL;
-
-	/* We're _really_ low on memory. Now we just
-	 * wait for old buffer heads to become free due to
-	 * finishing IO.  Since this is an async request and
-	 * the reserve list is empty, we're sure there are 
-	 * async buffer heads in use.
-	 */
-	run_task_queue(&tq_disk);
-
-	free_more_memory();
-	goto try_again;
-}
-
-/*
  * Called when truncating a buffer on a page completely.
  */
 static void discard_buffer(struct buffer_head * bh)
 {
 	if (buffer_mapped(bh)) {
-		mark_buffer_clean(bh);
+		clear_buffer_dirty(bh);
 		lock_buffer(bh);
 		bh->b_bdev = NULL;
-		clear_bit(BH_Uptodate, &bh->b_state);
-		clear_bit(BH_Mapped, &bh->b_state);
-		clear_bit(BH_Req, &bh->b_state);
-		clear_bit(BH_New, &bh->b_state);
-		remove_from_queues(bh);
+		clear_buffer_mapped(bh);
+		clear_buffer_req(bh);
+		clear_buffer_new(bh);
 		unlock_buffer(bh);
 	}
 }
 
 /**
- * try_to_release_page - release old fs-specific metadata on a page
+ * try_to_release_page() - release old fs-specific metadata on a page
+ *
+ * @page: the page which the kernel is trying to free
+ * @gfp_mask: memory allocation flags (and I/O mode)
+ *
+ * The address_space is to try to release any data against the page
+ * (presumably at page->private).  If the release was successful, return `1'.
+ * Otherwise return zero.
+ *
+ * The @gfp_mask argument specifies whether I/O may be performed to release
+ * this page (__GFP_IO), and whether the call may block (__GFP_WAIT).
  *
+ * NOTE: @gfp_mask may go away, and this function may become non-blocking.
  */
-
-int try_to_release_page(struct page * page, int gfp_mask)
+int try_to_release_page(struct page *page, int gfp_mask)
 {
 	struct address_space * const mapping = page->mapping;
 
 	if (!PageLocked(page))
 		BUG();
+	if (PageWriteback(page))
+		return 0;
 	
 	if (mapping && mapping->a_ops->releasepage)
 		return mapping->a_ops->releasepage(page, gfp_mask);
-	return try_to_free_buffers(page, gfp_mask);
+	return try_to_free_buffers(page);
 }
 
-/*
- * We don't have to release all buffers here, but
- * we have to be sure that no dirty buffer is left
- * and no IO is going on (no buffer is locked), because
- * we have truncated the file and are going to free the
- * blocks on-disk..
+/**
+ * block_flushpage - invalidate part of all of a buffer-backed page
+ *
+ * @page: the page which is affected
+ * @offset: the index of the truncation point
+ *
+ * block_flushpage() should be called block_invalidatepage().  It is
+ * called when all or part of the page has become invalidatedby a truncate
+ * operation.
+ *
+ * block_flushpage() does not have to release all buffers, but it must
+ * ensure that no dirty buffer is left outside @offset and that no I/O
+ * is underway against any of the blocks which are outside the truncation
+ * point.  Because the caller is about to free (and possibly reuse) those
+ * blocks on-disk.
  */
-int discard_bh_page(struct page *page, unsigned long offset, int drop_pagecache)
+int block_flushpage(struct page *page, unsigned long offset)
 {
 	struct buffer_head *head, *bh, *next;
 	unsigned int curr_off = 0;
@@ -1358,7 +1211,7 @@
 		next = bh->b_this_page;
 
 		/*
-		 * is this block fully flushed?
+		 * is this block fully invalidated?
 		 */
 		if (offset <= curr_off)
 			discard_buffer(bh);
@@ -1367,16 +1220,11 @@
 	} while (bh != head);
 
 	/*
-	 * subtle. We release buffer-heads only if this is
-	 * the 'final' flushpage. We have invalidated the get_block
-	 * cached value unconditionally, so real IO is not
-	 * possible anymore.
-	 *
-	 * If the free doesn't work out, the buffers can be
-	 * left around - they just turn into anonymous buffers
-	 * instead.
+	 * We release buffers only if the entire page is being invalidated.
+	 * The get_block cached value has been unconditionally invalidated,
+	 * so real IO is not possible anymore.
 	 */
-	if (!offset) {
+	if (offset == 0) {
 		if (!try_to_release_page(page, 0))
 			return 0;
 	}
@@ -1384,24 +1232,36 @@
 	return 1;
 }
 
-void create_empty_buffers(struct page *page, unsigned long blocksize)
+/*
+ * We attach and possibly dirty the buffers atomically wrt
+ * __set_page_dirty_buffers() via i_bufferlist_lock.  try_to_free_buffers
+ * is already excluded via the page lock.
+ */
+void create_empty_buffers(struct page *page,
+			unsigned long blocksize, unsigned long b_state)
 {
 	struct buffer_head *bh, *head, *tail;
 
-	/* FIXME: create_buffers should fail if there's no enough memory */
 	head = create_buffers(page, blocksize, 1);
-	if (page_has_buffers(page))
-		BUG();
-
 	bh = head;
 	do {
 		bh->b_end_io = NULL;
+		bh->b_state |= b_state;
 		tail = bh;
 		bh = bh->b_this_page;
 	} while (bh);
 	tail->b_this_page = head;
-	set_page_buffers(page, head);
-	page_cache_get(page);
+
+	spin_lock(&page->mapping->host->i_bufferlist_lock);
+	if (PageDirty(page)) {
+		bh = head;
+		do {
+			set_buffer_dirty(bh);
+			bh = bh->b_this_page;
+		} while (bh != head);
+	}
+	__set_page_buffers(page, head);
+	spin_unlock(&page->mapping->host->i_bufferlist_lock);
 }
 EXPORT_SYMBOL(create_empty_buffers);
 
@@ -1416,16 +1276,19 @@
  * don't want to mark the alias unmapped, for example - it would confuse
  * anyone who might pick it with bread() afterwards...
  */
-
-static void unmap_underlying_metadata(struct buffer_head * bh)
+static void unmap_underlying_metadata(struct buffer_head *bh)
 {
 	struct buffer_head *old_bh;
 
-	old_bh = __get_hash_table(bh->b_bdev, bh->b_blocknr, bh->b_size);
+	old_bh = __get_hash_table(bh->b_bdev, bh->b_blocknr, 0);
 	if (old_bh) {
-		mark_buffer_clean(old_bh);
+#if 0	/* This happens.  Later. */
+		if (buffer_dirty(old_bh))
+			buffer_error();
+#endif
+		clear_buffer_dirty(old_bh);
 		wait_on_buffer(old_bh);
-		clear_bit(BH_Req, &old_bh->b_state);
+		clear_buffer_req(old_bh);
 		__brelse(old_bh);
 	}
 }
@@ -1444,98 +1307,164 @@
  */
 
 /*
- * block_write_full_page() is SMP threaded - the kernel lock is not held.
+ * While block_write_full_page is writing back the dirty buffers under
+ * the page lock, whoever dirtied the buffers may decide to clean them
+ * again at any time.  We handle that by only looking at the buffer
+ * state inside lock_buffer().
  */
-static int __block_write_full_page(struct inode *inode, struct page *page, get_block_t *get_block)
+static int __block_write_full_page(struct inode *inode,
+			struct page *page, get_block_t *get_block)
 {
-	int err, i;
+	int err;
 	unsigned long block;
+	unsigned long last_block;
 	struct buffer_head *bh, *head;
-	int need_unlock;
+	int nr_underway = 0;
 
-	if (!PageLocked(page))
-		BUG();
+	BUG_ON(!PageLocked(page));
 
-	if (!page_has_buffers(page))
-		create_empty_buffers(page, 1 << inode->i_blkbits);
-	head = page_buffers(page);
+	last_block = (inode->i_size - 1) >> inode->i_blkbits;
 
-	block = page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
+	if (!page_has_buffers(page)) {
+		if (S_ISBLK(inode->i_mode))
+			buffer_error();
+		if (!PageUptodate(page))
+			buffer_error();
+		create_empty_buffers(page, 1 << inode->i_blkbits,
+					(1 << BH_Dirty)|(1 << BH_Uptodate));
+	}
 
+	block = page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
+	head = page_buffers(page);
 	bh = head;
-	i = 0;
 
-	/* Stage 1: make sure we have all the buffers mapped! */
+	/*
+	 * Get all the dirty buffers mapped to disk addresses and
+	 * handle any aliases from the underlying blockdev's mapping.
+	 */
 	do {
-		/*
-		 * If the buffer isn't up-to-date, we can't be sure
-		 * that the buffer has been initialized with the proper
-		 * block number information etc..
-		 *
-		 * Leave it to the low-level FS to make all those
-		 * decisions (block #0 may actually be a valid block)
-		 */
-		if (!buffer_mapped(bh)) {
+		if (block > last_block) {
+			if (buffer_dirty(bh))
+				buffer_error();
+			if (buffer_mapped(bh))
+				buffer_error();
+			/*
+			 * NOTE: this buffer can only be marked uptodate
+			 * because we know that block_write_full_page has
+			 * zeroed it out.  That seems unnecessary and may go
+			 * away.
+			 */
+			set_buffer_uptodate(bh);
+		} else if (!buffer_mapped(bh) && buffer_dirty(bh)) {
+			if (buffer_new(bh))
+				buffer_error();
 			err = get_block(inode, block, bh, 1);
 			if (err)
-				goto out;
-			if (buffer_new(bh))
+				goto recover;
+			if (buffer_new(bh)) {
+				/* blockdev mappings never come here */
+				clear_buffer_new(bh);
 				unmap_underlying_metadata(bh);
+			}
 		}
 		bh = bh->b_this_page;
 		block++;
 	} while (bh != head);
 
-	/* Stage 2: lock the buffers, mark them clean */
 	do {
-		lock_buffer(bh);
-		set_buffer_async_io(bh);
-		set_bit(BH_Uptodate, &bh->b_state);
-		clear_bit(BH_Dirty, &bh->b_state);
+		get_bh(bh);
+		if (buffer_dirty(bh)) {
+			lock_buffer(bh);
+			if (buffer_dirty(bh)) {
+				if (!buffer_mapped(bh))
+					buffer_error();
+				if (!buffer_uptodate(bh))
+					buffer_error();
+				set_buffer_async_io(bh);
+			} else {
+				unlock_buffer(bh);
+			}
+		}
 		bh = bh->b_this_page;
 	} while (bh != head);
 
-	/* Stage 3: submit the IO */
+	BUG_ON(PageWriteback(page));
+	SetPageWriteback(page);		/* Keeps try_to_free_buffers() away */
+	unlock_page(page);
+
+	/*
+	 * The page may come unlocked any time after the *first* submit_bh()
+	 * call.  Be careful with its buffers.
+	 */
 	do {
 		struct buffer_head *next = bh->b_this_page;
-		submit_bh(WRITE, bh);
+		if (buffer_async(bh)) {
+			clear_buffer_dirty(bh);
+			submit_bh(WRITE, bh);
+			nr_underway++;
+		}
+		put_bh(bh);
 		bh = next;
 	} while (bh != head);
 
-	/* Done - end_buffer_io_async will unlock */
-	SetPageUptodate(page);
-	return 0;
-
-out:
+	err = 0;
+done:
+	if (nr_underway == 0) {
+		/*
+		 * The page was marked dirty, but the buffers were
+		 * clean.  Someone wrote them back by hand with
+		 * ll_rw_block/submit_bh.  A rare case.
+		 */
+		int uptodate = 1;
+		do {
+			if (!buffer_uptodate(bh)) {
+				uptodate = 0;
+				break;
+			}
+			bh = bh->b_this_page;
+		} while (bh != head);
+		if (uptodate)
+			SetPageUptodate(page);
+		end_page_writeback(page);
+	}
+	return err;
+recover:
 	/*
 	 * ENOSPC, or some other error.  We may already have added some
 	 * blocks to the file, so we need to write these out to avoid
 	 * exposing stale data.
+	 * The page is currently locked and not marked for writeback
 	 */
 	ClearPageUptodate(page);
 	bh = head;
-	need_unlock = 1;
 	/* Recovery: lock and submit the mapped buffers */
 	do {
 		if (buffer_mapped(bh)) {
 			lock_buffer(bh);
 			set_buffer_async_io(bh);
-			need_unlock = 0;
+		} else {
+			/*
+			 * The buffer may have been set dirty during
+			 * attachment to a dirty page.
+			 */
+			clear_buffer_dirty(bh);
 		}
 		bh = bh->b_this_page;
 	} while (bh != head);
 	do {
 		struct buffer_head *next = bh->b_this_page;
 		if (buffer_mapped(bh)) {
-			set_bit(BH_Uptodate, &bh->b_state);
-			clear_bit(BH_Dirty, &bh->b_state);
+			set_buffer_uptodate(bh);
+			clear_buffer_dirty(bh);
 			submit_bh(WRITE, bh);
+			nr_underway++;
 		}
 		bh = next;
 	} while (bh != head);
-	if (need_unlock)
-		UnlockPage(page);
-	return err;
+	BUG_ON(PageWriteback(page));
+	SetPageWriteback(page);
+	unlock_page(page);
+	goto done;
 }
 
 static int __block_prepare_write(struct inode *inode, struct page *page,
@@ -1548,9 +1477,14 @@
 	struct buffer_head *bh, *head, *wait[2], **wait_bh=wait;
 	char *kaddr = kmap(page);
 
+	BUG_ON(!PageLocked(page));
+	BUG_ON(from > PAGE_CACHE_SIZE);
+	BUG_ON(to > PAGE_CACHE_SIZE);
+	BUG_ON(from > to);
+
 	blocksize = 1 << inode->i_blkbits;
 	if (!page_has_buffers(page))
-		create_empty_buffers(page, blocksize);
+		create_empty_buffers(page, blocksize, 0);
 	head = page_buffers(page);
 
 	bbits = inode->i_blkbits;
@@ -1558,35 +1492,38 @@
 
 	for(bh = head, block_start = 0; bh != head || !block_start;
 	    block++, block_start=block_end, bh = bh->b_this_page) {
-		if (!bh)
-			BUG();
-		block_end = block_start+blocksize;
-		if (block_end <= from)
+		block_end = block_start + blocksize;
+		if (block_end <= from || block_start >= to) {
+			if (PageUptodate(page))
+				set_buffer_uptodate(bh);
 			continue;
-		if (block_start >= to)
-			break;
-		clear_bit(BH_New, &bh->b_state);
+		}
+		clear_buffer_new(bh);
 		if (!buffer_mapped(bh)) {
 			err = get_block(inode, block, bh, 1);
 			if (err)
 				goto out;
 			if (buffer_new(bh)) {
+				clear_buffer_new(bh);
 				unmap_underlying_metadata(bh);
-				if (Page_Uptodate(page)) {
-					set_bit(BH_Uptodate, &bh->b_state);
+				if (PageUptodate(page)) {
+					if (!buffer_mapped(bh))
+						buffer_error();
+					set_buffer_uptodate(bh);
 					continue;
 				}
 				if (block_end > to)
 					memset(kaddr+to, 0, block_end-to);
 				if (block_start < from)
-					memset(kaddr+block_start, 0, from-block_start);
+					memset(kaddr+block_start,
+						0, from-block_start);
 				if (block_end > to || block_start < from)
 					flush_dcache_page(page);
 				continue;
 			}
 		}
-		if (Page_Uptodate(page)) {
-			set_bit(BH_Uptodate, &bh->b_state);
+		if (PageUptodate(page)) {
+			set_buffer_uptodate(bh);
 			continue; 
 		}
 		if (!buffer_uptodate(bh) &&
@@ -1619,10 +1556,11 @@
 		if (block_start >= to)
 			break;
 		if (buffer_new(bh)) {
+			clear_buffer_new(bh);
 			if (buffer_uptodate(bh))
-				printk(KERN_ERR "%s: zeroing uptodate buffer!\n", __FUNCTION__);
+				buffer_error();
 			memset(kaddr+block_start, 0, bh->b_size);
-			set_bit(BH_Uptodate, &bh->b_state);
+			set_buffer_uptodate(bh);
 			mark_buffer_dirty(bh);
 		}
 next_bh:
@@ -1636,7 +1574,7 @@
 		unsigned from, unsigned to)
 {
 	unsigned block_start, block_end;
-	int partial = 0, need_balance_dirty = 0;
+	int partial = 0;
 	unsigned blocksize;
 	struct buffer_head *bh, *head;
 
@@ -1650,21 +1588,15 @@
 			if (!buffer_uptodate(bh))
 				partial = 1;
 		} else {
-			set_bit(BH_Uptodate, &bh->b_state);
-			if (!atomic_set_buffer_dirty(bh)) {
-				__mark_dirty(bh);
-				buffer_insert_inode_data_queue(bh, inode);
-				need_balance_dirty = 1;
-			}
+			set_buffer_uptodate(bh);
+			mark_buffer_dirty(bh);
 		}
 	}
 
-	if (need_balance_dirty)
-		balance_dirty();
 	/*
-	 * is this a partial write that happened to make all buffers
+	 * If this is a partial write which happened to make all buffers
 	 * uptodate then we can optimize away a bogus readpage() for
-	 * the next read(). Here we 'discover' wether the page went
+	 * the next read(). Here we 'discover' whether the page went
 	 * uptodate as a result of this (potentially partial) write.
 	 */
 	if (!partial)
@@ -1676,7 +1608,7 @@
  * Generic "read page" function for block devices that have the normal
  * get_block functionality. This is most of the block device filesystems.
  * Reads the page asynchronously --- the unlock_buffer() and
- * mark_buffer_uptodate() functions propagate buffer state into the
+ * set/clear_buffer_uptodate() functions propagate buffer state into the
  * page struct once IO has completed.
  */
 int block_read_full_page(struct page *page, get_block_t *get_block)
@@ -1689,9 +1621,11 @@
 
 	if (!PageLocked(page))
 		PAGE_BUG(page);
+	if (PageUptodate(page))
+		buffer_error();
 	blocksize = 1 << inode->i_blkbits;
 	if (!page_has_buffers(page))
-		create_empty_buffers(page, blocksize);
+		create_empty_buffers(page, blocksize, 0);
 	head = page_buffers(page);
 
 	blocks = PAGE_CACHE_SIZE >> inode->i_blkbits;
@@ -1714,16 +1648,17 @@
 				memset(kmap(page) + i*blocksize, 0, blocksize);
 				flush_dcache_page(page);
 				kunmap(page);
-				set_bit(BH_Uptodate, &bh->b_state);
+				set_buffer_uptodate(bh);
 				continue;
 			}
-			/* get_block() might have updated the buffer synchronously */
+			/*
+			 * get_block() might have updated the buffer
+			 * synchronously
+			 */
 			if (buffer_uptodate(bh))
 				continue;
 		}
-
-		arr[nr] = bh;
-		nr++;
+		arr[nr++] = bh;
 	} while (i++, iblock++, (bh = bh->b_this_page) != head);
 
 	if (!nr) {
@@ -1733,7 +1668,7 @@
 		 */
 		if (!PageError(page))
 			SetPageUptodate(page);
-		UnlockPage(page);
+		unlock_page(page);
 		return 0;
 	}
 
@@ -1741,13 +1676,25 @@
 	for (i = 0; i < nr; i++) {
 		struct buffer_head * bh = arr[i];
 		lock_buffer(bh);
+		if (buffer_uptodate(bh))
+			buffer_error();
+		if (buffer_dirty(bh))
+			buffer_error();
 		set_buffer_async_io(bh);
 	}
 
-	/* Stage 3: start the IO */
-	for (i = 0; i < nr; i++)
-		submit_bh(READ, arr[i]);
-
+	/*
+	 * Stage 3: start the IO.  Check for uptodateness
+	 * inside the buffer lock in case another process reading
+	 * the underlying blockdev brought it uptodate (the sct fix).
+	 */
+	for (i = 0; i < nr; i++) {
+		struct buffer_head * bh = arr[i];
+		if (buffer_uptodate(bh))
+			end_buffer_io_async(bh, 1);
+		else
+			submit_bh(READ, bh);
+	}
 	return 0;
 }
 
@@ -1789,7 +1736,7 @@
 	if (!err) {
 		err = mapping->a_ops->commit_write(NULL, page, offset, offset);
 	}
-	UnlockPage(page);
+	unlock_page(page);
 	page_cache_release(page);
 	if (err > 0)
 		err = 0;
@@ -1802,7 +1749,8 @@
  * We may have to extend the file.
  */
 
-int cont_prepare_write(struct page *page, unsigned offset, unsigned to, get_block_t *get_block, unsigned long *bytes)
+int cont_prepare_write(struct page *page, unsigned offset,
+		unsigned to, get_block_t *get_block, unsigned long *bytes)
 {
 	struct address_space *mapping = page->mapping;
 	struct inode *inode = mapping->host;
@@ -1820,7 +1768,7 @@
 			goto out;
 		/* we might sleep */
 		if (*bytes>>PAGE_CACHE_SHIFT != pgpos) {
-			UnlockPage(new_page);
+			unlock_page(new_page);
 			page_cache_release(new_page);
 			continue;
 		}
@@ -1836,9 +1784,10 @@
 		kaddr = page_address(new_page);
 		memset(kaddr+zerofrom, 0, PAGE_CACHE_SIZE-zerofrom);
 		flush_dcache_page(new_page);
-		__block_commit_write(inode, new_page, zerofrom, PAGE_CACHE_SIZE);
+		__block_commit_write(inode, new_page,
+				zerofrom, PAGE_CACHE_SIZE);
 		kunmap(new_page);
-		UnlockPage(new_page);
+		unlock_page(new_page);
 		page_cache_release(new_page);
 	}
 
@@ -1877,7 +1826,7 @@
 out_unmap:
 	ClearPageUptodate(new_page);
 	kunmap(new_page);
-	UnlockPage(new_page);
+	unlock_page(new_page);
 	page_cache_release(new_page);
 out:
 	return status;
@@ -1917,7 +1866,8 @@
 	return 0;
 }
 
-int block_truncate_page(struct address_space *mapping, loff_t from, get_block_t *get_block)
+int block_truncate_page(struct address_space *mapping,
+			loff_t from, get_block_t *get_block)
 {
 	unsigned long index = from >> PAGE_CACHE_SHIFT;
 	unsigned offset = from & (PAGE_CACHE_SIZE-1);
@@ -1943,7 +1893,7 @@
 		goto out;
 
 	if (!page_has_buffers(page))
-		create_empty_buffers(page, blocksize);
+		create_empty_buffers(page, blocksize, 0);
 
 	/* Find the buffer that contains "offset" */
 	bh = page_buffers(page);
@@ -1966,8 +1916,8 @@
 	}
 
 	/* Ok, it's mapped. Make sure it's up-to-date */
-	if (Page_Uptodate(page))
-		set_bit(BH_Uptodate, &bh->b_state);
+	if (PageUptodate(page))
+		set_buffer_uptodate(bh);
 
 	if (!buffer_uptodate(bh)) {
 		err = -EIO;
@@ -1982,91 +1932,44 @@
 	flush_dcache_page(page);
 	kunmap(page);
 
-	__mark_buffer_dirty(bh);
+	mark_buffer_dirty(bh);
 	err = 0;
 
 unlock:
-	UnlockPage(page);
+	unlock_page(page);
 	page_cache_release(page);
 out:
 	return err;
 }
 
+/*
+ * The generic ->writepage function for buffer-backed address_spaces
+ */
 int block_write_full_page(struct page *page, get_block_t *get_block)
 {
-	struct inode *inode = page->mapping->host;
-	unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+	struct inode * const inode = page->mapping->host;
+	const unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT;
 	unsigned offset;
-	int err;
+	char *kaddr;
 
-	/* easy case */
+	/* Is the page fully inside i_size? */
 	if (page->index < end_index)
 		return __block_write_full_page(inode, page, get_block);
 
-	/* things got complicated... */
+	/* Is the page fully outside i_size? (truncate in progress) */
 	offset = inode->i_size & (PAGE_CACHE_SIZE-1);
-	/* OK, are we completely out? */
 	if (page->index >= end_index+1 || !offset) {
-		UnlockPage(page);
+		unlock_page(page);
 		return -EIO;
 	}
 
-	/* Sigh... will have to work, then... */
-	err = __block_prepare_write(inode, page, 0, offset, get_block);
-	if (!err) {
-		memset(page_address(page) + offset, 0, PAGE_CACHE_SIZE - offset);
-		flush_dcache_page(page);
-		__block_commit_write(inode,page,0,offset);
-done:
-		kunmap(page);
-		UnlockPage(page);
-		return err;
-	}
-	ClearPageUptodate(page);
-	goto done;
-}
-
-/*
- * Commence writeout of all the buffers against a page.  The
- * page must be locked.   Returns zero on success or a negative
- * errno.
- */
-int writeout_one_page(struct page *page)
-{
-	struct buffer_head *bh, *head = page_buffers(page);
-
-	if (!PageLocked(page))
-		BUG();
-	bh = head;
-	do {
-		if (buffer_locked(bh) || !buffer_dirty(bh) || !buffer_uptodate(bh))
-			continue;
-
-		bh->b_flushtime = jiffies;
-		ll_rw_block(WRITE, 1, &bh);	
-	} while ((bh = bh->b_this_page) != head);
-	return 0;
-}
-EXPORT_SYMBOL(writeout_one_page);
-
-/*
- * Wait for completion of I/O of all buffers against a page.  The page
- * must be locked.  Returns zero on success or a negative errno.
- */
-int waitfor_one_page(struct page *page)
-{
-	int error = 0;
-	struct buffer_head *bh, *head = page_buffers(page);
-
-	bh = head;
-	do {
-		wait_on_buffer(bh);
-		if (buffer_req(bh) && !buffer_uptodate(bh))
-			error = -EIO;
-	} while ((bh = bh->b_this_page) != head);
-	return error;
+	/* The page straddles i_size */
+	kaddr = kmap(page);
+	memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
+	flush_dcache_page(page);
+	kunmap(page);
+	return __block_write_full_page(inode, page, get_block);
 }
-EXPORT_SYMBOL(waitfor_one_page);
 
 sector_t generic_block_bmap(struct address_space *mapping, sector_t block,
 			    get_block_t *get_block)
@@ -2079,7 +1982,9 @@
 	return tmp.b_blocknr;
 }
 
-int generic_direct_IO(int rw, struct inode * inode, struct kiobuf * iobuf, unsigned long blocknr, int blocksize, get_block_t * get_block)
+int generic_direct_IO(int rw, struct inode *inode,
+			struct kiobuf *iobuf, unsigned long blocknr,
+			int blocksize, get_block_t *get_block)
 {
 	int i, nr_blocks, retval;
 	sector_t *blocks = iobuf->blocks;
@@ -2114,7 +2019,8 @@
 	}
 
 	/* This does not understand multi-device filesystems currently */
-	retval = brw_kiovec(rw, 1, &iobuf, inode->i_sb->s_bdev, blocks, blocksize);
+	retval = brw_kiovec(rw, 1, &iobuf,
+			inode->i_sb->s_bdev, blocks, blocksize);
 
  out:
 	return retval;
@@ -2185,21 +2091,24 @@
  * before I/O is complete. You then have to check page->locked
  * and page->uptodate.
  *
- * brw_page() is SMP-safe, although it's being called with the
- * kernel lock held - but the code is ready.
- *
  * FIXME: we need a swapper_inode->get_block function to remove
  *        some of the bmap kludges and interface ugliness here.
+ *
+ * NOTE: unlike file pages, swap pages are locked while under writeout.
+ * This is to avoid a deadlock which occurs when free_swap_and_cache()
+ * calls block_flushpage() under spinlock and hits a locked buffer, and
+ * schedules under spinlock.   Another approach would be to teach
+ * find_trylock_page() to also trylock the page's writeback flags.
  */
-int brw_page(int rw, struct page *page, struct block_device *bdev, sector_t b[], int size)
+int brw_page(int rw, struct page *page,
+		struct block_device *bdev, sector_t b[], int size)
 {
 	struct buffer_head *head, *bh;
 
-	if (!PageLocked(page))
-		panic("brw_page: page not locked for I/O");
+	BUG_ON(!PageLocked(page));
 
 	if (!page_has_buffers(page))
-		create_empty_buffers(page, size);
+		create_empty_buffers(page, size, 0);
 	head = bh = page_buffers(page);
 
 	/* Stage 1: lock all the buffers */
@@ -2207,7 +2116,9 @@
 		lock_buffer(bh);
 		bh->b_blocknr = *(b++);
 		bh->b_bdev = bdev;
-		set_bit(BH_Mapped, &bh->b_state);
+		set_buffer_mapped(bh);
+		if (rw == WRITE)
+			set_buffer_uptodate(bh);
 		set_buffer_async_io(bh);
 		bh = bh->b_this_page;
 	} while (bh != head);
@@ -2244,382 +2155,121 @@
 	 * OTOH it's obviously correct and should make the page up-to-date.
 	 */
 	err = mapping->a_ops->readpage(NULL, page);
-	wait_on_page(page);
+	wait_on_page_locked(page);
 	page_cache_release(page);
 	if (err < 0)
 		goto fail;
 	mark_inode_dirty(inode);
 	return 0;
 fail_map:
-	UnlockPage(page);
+	unlock_page(page);
 	page_cache_release(page);
 fail:
 	return err;
 }
 
-static inline void link_dev_buffers(struct page * page, struct buffer_head *head)
-{
-	struct buffer_head *bh, *tail;
-
-	bh = head;
-	do {
-		tail = bh;
-		bh = bh->b_this_page;
-	} while (bh);
-	tail->b_this_page = head;
-	set_page_buffers(page, head);
-	page_cache_get(page);
-}
-
-/*
- * Create the page-cache page that contains the requested block
- */
-static struct page * grow_dev_page(struct block_device *bdev, unsigned long index, int size)
-{
-	struct page * page;
-	struct buffer_head *bh;
-
-	page = find_or_create_page(bdev->bd_inode->i_mapping, index, GFP_NOFS);
-	if (!page)
-		return NULL;
-
-	if (!PageLocked(page))
-		BUG();
-
-	if (page_has_buffers(page)) {
-		bh = page_buffers(page);
-		if (bh->b_size == size)
-			return page;
-		if (!try_to_free_buffers(page, GFP_NOFS))
-			goto failed;
-	}
-
-	bh = create_buffers(page, size, 0);
-	if (!bh)
-		goto failed;
-	link_dev_buffers(page, bh);
-	return page;
-
-failed:
-	UnlockPage(page);
-	page_cache_release(page);
-	return NULL;
-}
-
-static void hash_page_buffers(struct page *page, struct block_device *bdev, int block, int size)
-{
-	struct buffer_head *head = page_buffers(page);
-	struct buffer_head *bh = head;
-	unsigned int uptodate;
-
-	uptodate = 1 << BH_Mapped;
-	if (Page_Uptodate(page))
-		uptodate |= 1 << BH_Uptodate;
-
-	write_lock(&hash_table_lock);
-	do {
-		if (!(bh->b_state & (1 << BH_Mapped))) {
-			init_buffer(bh, NULL, NULL);
-			bh->b_bdev = bdev;
-			bh->b_blocknr = block;
-			bh->b_state = uptodate;
-		}
-
-		/* Insert the buffer into the hash lists if necessary */
-		if (!bh->b_pprev)
-			__insert_into_hash_list(bh);
-
-		block++;
-		bh = bh->b_this_page;
-	} while (bh != head);
-	write_unlock(&hash_table_lock);
-}
-
 /*
- * Try to increase the number of buffers available: the size argument
- * is used to determine what kind of buffers we want.
+ * Sanity checks for try_to_free_buffers.
  */
-static int grow_buffers(struct block_device *bdev, unsigned long block, int size)
+static void check_ttfb_buffer(struct page *page, struct buffer_head *bh)
 {
-	struct page * page;
-	unsigned long index;
-	int sizebits;
-
-	/* Size must be multiple of hard sectorsize */
-	if (size & (bdev_hardsect_size(bdev)-1))
-		BUG();
-	/* Size must be within 512 bytes and PAGE_SIZE */
-	if (size < 512 || size > PAGE_SIZE)
-		BUG();
-
-	sizebits = -1;
-	do {
-		sizebits++;
-	} while ((size << sizebits) < PAGE_SIZE);
-
-	index = block >> sizebits;
-	block = index << sizebits;
-
-	/* Create a page with the proper size buffers.. */
-	page = grow_dev_page(bdev, index, size);
-
-	if (!page)
-		return 0;
-
-	/* Hash in the buffers on the hash list */
-	hash_page_buffers(page, bdev, block, size);
-	UnlockPage(page);
-	page_cache_release(page);
-
-	/* We hashed up this page, so increment buffermem */
-	atomic_inc(&buffermem_pages);
-	return 1;
-}
-
-static int sync_page_buffers(struct buffer_head *head, unsigned int gfp_mask)
-{
-	struct buffer_head * bh = head;
-	int tryagain = 0;
-
-	do {
-		if (!buffer_dirty(bh) && !buffer_locked(bh))
-			continue;
-
-		/* Don't start IO first time around.. */
-		if (!test_and_set_bit(BH_Wait_IO, &bh->b_state))
-			continue;
-
-		/* Second time through we start actively writing out.. */
-		if (test_and_set_bit(BH_Lock, &bh->b_state)) {
-			if (!test_bit(BH_launder, &bh->b_state))
-				continue;
-			wait_on_buffer(bh);
-			tryagain = 1;
-			continue;
-		}
-
-		if (!atomic_set_buffer_clean(bh)) {
-			unlock_buffer(bh);
-			continue;
+	if (!buffer_uptodate(bh)) {
+		if (PageUptodate(page) && page->mapping
+			&& buffer_mapped(bh)	/* discard_buffer */
+			&& S_ISBLK(page->mapping->host->i_mode))
+		{
+			buffer_error();
 		}
-
-		__mark_buffer_clean(bh);
-		get_bh(bh);
-		set_bit(BH_launder, &bh->b_state);
-		bh->b_end_io = end_buffer_io_sync;
-		submit_bh(WRITE, bh);
-		tryagain = 0;
-	} while ((bh = bh->b_this_page) != head);
-
-	return tryagain;
+	}
 }
 
 /*
- * Can the buffer be thrown out?
- */
-#define BUFFER_BUSY_BITS	((1<<BH_Dirty) | (1<<BH_Lock))
-#define buffer_busy(bh)		(atomic_read(&(bh)->b_count) | ((bh)->b_state & BUFFER_BUSY_BITS))
-
-/*
  * try_to_free_buffers() checks if all the buffers on this particular page
- * are unused, and free's the page if so.
+ * are unused, and releases them if so.
+ *
+ * Exclusion against try_to_free_buffers may be obtained by either
+ * locking the page or by holding its inode's i_bufferlist_lock.
+ *
+ * If the page is dirty but all the buffers are clean then we need to
+ * be sure to mark the page clean as well.  This is because the page
+ * may be against a block device, and a later reattachment of buffers
+ * to a dirty page will set *all* buffers dirty.  Which would corrupt
+ * filesystem data on the same device.
+ *
+ * The same applies to regular filesystem pages: if all the buffers are
+ * clean then we set the page clean and proceed.  To do that, we require
+ * total exclusion from __set_page_dirty_buffers().  That is obtained with
+ * i_bufferlist_lock.
  *
- * Wake up bdflush() if this fails - if we're running low on memory due
- * to dirty buffers, we need to flush them out as quickly as possible.
+ * Nobody should be calling try_to_free_buffers against a page which is
+ * eligible for set_page_dirty() treatment anyway - the page is clearly
+ * not freeable.  So we could just test page_count(page) here and complain
+ * then scram if it's wrong.
  *
- * NOTE: There are quite a number of ways that threads of control can
- *       obtain a reference to a buffer head within a page.  So we must
- *	 lock out all of these paths to cleanly toss the page.
+ * If any buffer is not uptodate then the entire page is set not uptodate,
+ * as the partial uptodateness information is about to be lost.
+ *
+ * try_to_free_buffers() is non-blocking.
  */
-int try_to_free_buffers(struct page * page, unsigned int gfp_mask)
+static inline int buffer_busy(struct buffer_head *bh)
 {
-	struct buffer_head * tmp, * bh = page_buffers(page);
+	return atomic_read(&bh->b_count) |
+		(bh->b_state & ((1 << BH_Dirty) | (1 << BH_Lock)));
+}
 
-	BUG_ON(!PageLocked(page));
-	BUG_ON(!bh);
+static /*inline*/ int drop_buffers(struct page *page)
+{
+	struct buffer_head *head = page_buffers(page);
+	struct buffer_head *bh;
+	int was_uptodate = 1;
 
-cleaned_buffers_try_again:
-	spin_lock(&lru_list_lock);
-	write_lock(&hash_table_lock);
-	tmp = bh;
+	bh = head;
 	do {
-		if (buffer_busy(tmp))
-			goto busy_buffer_page;
-		tmp = tmp->b_this_page;
-	} while (tmp != bh);
+		check_ttfb_buffer(page, bh);
+		if (buffer_busy(bh))
+			goto failed;
+		if (!buffer_uptodate(bh))
+			was_uptodate = 0;
+		bh = bh->b_this_page;
+	} while (bh != head);
 
-	spin_lock(&unused_list_lock);
-	tmp = bh;
+	if (!was_uptodate && PageUptodate(page))
+		buffer_error();
 
-	/* if this buffer was hashed, this page counts as buffermem */
-	if (bh->b_pprev)
-		atomic_dec(&buffermem_pages);
 	do {
-		struct buffer_head * p = tmp;
-		tmp = tmp->b_this_page;
-		remove_inode_queue(p);
-		__remove_from_queues(p);
-		__put_unused_buffer_head(p);
-	} while (tmp != bh);
-	spin_unlock(&unused_list_lock);
-
-	/* Wake up anyone waiting for buffer heads */
-	wake_up(&buffer_wait);
+		struct buffer_head *next = bh->b_this_page;
 
-	/* And free the page */
-	clear_page_buffers(page);
-	page_cache_release(page);
-	write_unlock(&hash_table_lock);
-	spin_unlock(&lru_list_lock);
+		__remove_inode_queue(bh);
+		free_buffer_head(bh);
+		bh = next;
+	} while (bh != head);
+	__clear_page_buffers(page);
 	return 1;
-
-busy_buffer_page:
-	/* Uhhuh, start writeback so that we don't end up with all dirty pages */
-	write_unlock(&hash_table_lock);
-	spin_unlock(&lru_list_lock);
-	if (gfp_mask & __GFP_IO) {
-		if ((gfp_mask & __GFP_HIGHIO) || !PageHighMem(page)) {
-			if (sync_page_buffers(bh, gfp_mask)) {
-				/* no IO or waiting next time */
-				gfp_mask = 0;
-				goto cleaned_buffers_try_again;
-			}
-		}
-	}
-	if (balance_dirty_state() >= 0)
-		wakeup_bdflush();
+failed:
 	return 0;
 }
-EXPORT_SYMBOL(try_to_free_buffers);
-
-/* ================== Debugging =================== */
-
-void show_buffers(void)
-{
-#ifdef CONFIG_SMP
-	struct buffer_head * bh;
-	int found = 0, locked = 0, dirty = 0, used = 0, lastused = 0;
-	int nlist;
-	static char *buf_types[NR_LIST] = { "CLEAN", "LOCKED", "DIRTY", };
-#endif
-
-	printk("Buffer memory:   %6dkB\n",
-			atomic_read(&buffermem_pages) << (PAGE_SHIFT-10));
-
-#ifdef CONFIG_SMP /* trylock does nothing on UP and so we could deadlock */
-	if (!spin_trylock(&lru_list_lock))
-		return;
-	for(nlist = 0; nlist < NR_LIST; nlist++) {
-		found = locked = dirty = used = lastused = 0;
-		bh = lru_list[nlist];
-		if(!bh) continue;
-
-		do {
-			found++;
-			if (buffer_locked(bh))
-				locked++;
-			if (buffer_dirty(bh))
-				dirty++;
-			if (atomic_read(&bh->b_count))
-				used++, lastused = found;
-			bh = bh->b_next_free;
-		} while (bh != lru_list[nlist]);
-		{
-			int tmp = nr_buffers_type[nlist];
-			if (found != tmp)
-				printk("%9s: BUG -> found %d, reported %d\n",
-				       buf_types[nlist], found, tmp);
-		}
-		printk("%9s: %d buffers, %lu kbyte, %d used (last=%d), "
-		       "%d locked, %d dirty\n",
-		       buf_types[nlist], found, size_buffers_type[nlist]>>10,
-		       used, lastused, locked, dirty);
-	}
-	spin_unlock(&lru_list_lock);
-#endif
-}
-
-/* ===================== Init ======================= */
 
-/*
- * allocate the hash table and init the free list
- * Use gfp() for the hash table to decrease TLB misses, use
- * SLAB cache for buffer heads.
- */
-void __init buffer_init(unsigned long mempages)
+int try_to_free_buffers(struct page *page)
 {
-	int order, i;
-	unsigned int nr_hash;
-
-	/* The buffer cache hash table is less important these days,
-	 * trim it a bit.
-	 */
-	mempages >>= 14;
-
-	mempages *= sizeof(struct buffer_head *);
-
-	for (order = 0; (1 << order) < mempages; order++)
-		;
-
-	/* try to allocate something until we get it or we're asking
-	   for something that is really too small */
-
-	do {
-		unsigned long tmp;
-
-		nr_hash = (PAGE_SIZE << order) / sizeof(struct buffer_head *);
-		bh_hash_mask = (nr_hash - 1);
-
-		tmp = nr_hash;
-		bh_hash_shift = 0;
-		while((tmp >>= 1UL) != 0UL)
-			bh_hash_shift++;
-
-		hash_table = (struct buffer_head **)
-		    __get_free_pages(GFP_ATOMIC, order);
-	} while (hash_table == NULL && --order > 0);
-	printk("Buffer-cache hash table entries: %d (order: %d, %ld bytes)\n",
-	       nr_hash, order, (PAGE_SIZE << order));
+	struct inode *inode;
+	int ret = 0;
 
-	if (!hash_table)
-		panic("Failed to allocate buffer hash table\n");
-
-	/* Setup hash chains. */
-	for(i = 0; i < nr_hash; i++)
-		hash_table[i] = NULL;
-
-	/* Setup lru lists. */
-	for(i = 0; i < NR_LIST; i++)
-		lru_list[i] = NULL;
-
-}
-
-/* 
- * Here we attempt to write back old buffers.  We also try to flush inodes 
- * and supers as well, since this function is essentially "update", and 
- * otherwise there would be no way of ensuring that these quantities ever 
- * get written back.  Ideally, we would have a timestamp on the inodes
- * and superblocks so that we could write back only the old ones as well
- */
-
-static void sync_old_buffers(unsigned long dummy)
-{
-	sync_unlocked_inodes();
-	sync_supers();
+	BUG_ON(!PageLocked(page));
+	if (PageWriteback(page))
+		return 0;
 
-	for (;;) {
-		struct buffer_head *bh;
+	if (page->mapping == NULL)	/* swapped-in anon page */
+		return drop_buffers(page);
 
-		spin_lock(&lru_list_lock);
-		bh = lru_list[BUF_DIRTY];
-		if (!bh || time_before(jiffies, bh->b_flushtime))
-			break;
-		if (write_some_buffers(NULL))
-			continue;
-		return;
-	}
-	spin_unlock(&lru_list_lock);
+	inode = page->mapping->host;
+	spin_lock(&inode->i_bufferlist_lock);
+	ret = drop_buffers(page);
+	if (ret)
+		ClearPageDirty(page);
+	spin_unlock(&inode->i_bufferlist_lock);
+	return ret;
 }
+EXPORT_SYMBOL(try_to_free_buffers);
 
 int block_sync_page(struct page *page)
 {
@@ -2627,98 +2277,77 @@
 	return 0;
 }
 
-/* This is the interface to bdflush.  As we get more sophisticated, we can
- * pass tuning parameters to this "process", to adjust how it behaves. 
- * We would want to verify each parameter, however, to make sure that it 
- * is reasonable. */
-
+/*
+ * There are no bdflush tunables left.  But distributions are
+ * still running obsolete flush daemons, so we terminate them here.
+ */
 asmlinkage long sys_bdflush(int func, long data)
 {
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
-
-	if (func == 1) {
-		/* do_exit directly and let kupdate to do its work alone. */
+	if (func == 1)
 		do_exit(0);
-#if 0 /* left here as it's the only example of lazy-mm-stuff used from
-	 a syscall that doesn't care about the current mm context. */
-		int error;
-		struct mm_struct *user_mm;
+	return 0;
+}
 
-		/*
-		 * bdflush will spend all of it's time in kernel-space,
-		 * without touching user-space, so we can switch it into
-		 * 'lazy TLB mode' to reduce the cost of context-switches
-		 * to and from bdflush.
-		 */
-		user_mm = start_lazy_tlb();
-		error = sync_old_buffers();
-		end_lazy_tlb(user_mm);
-		return error;
-#endif
-	}
+void wakeup_bdflush(void)
+{
+ 	pdflush_flush(0);
+}
 
-	/* Basically func 1 means read param 1, 2 means write param 1, etc */
-	if (func >= 2) {
-		int i = (func-2) >> 1;
-		if (i >= 0 && i < N_PARAM) {
-			if ((func & 1) == 0)
-				return put_user(bdf_prm.data[i], (int*)data);
-
-			if (data >= bdflush_min[i] && data <= bdflush_max[i]) {
-				bdf_prm.data[i] = data;
-				return 0;
-			}
-		}
-		return -EINVAL;
-	}
+/*
+ * Buffer-head allocation
+ */
+static kmem_cache_t *bh_cachep;
+static mempool_t *bh_mempool;
 
-	/* Having func 0 used to launch the actual bdflush and then never
-	 * return (unless explicitly killed). We return zero here to 
-	 * remain semi-compatible with present update(8) programs.
-	 */
-	return 0;
+struct buffer_head *alloc_buffer_head(int async)
+{
+	return mempool_alloc(bh_mempool, GFP_NOFS);
 }
+EXPORT_SYMBOL(alloc_buffer_head);
 
-static void bdflush(unsigned long pexclude)
+void free_buffer_head(struct buffer_head *bh)
 {
-	while (balance_dirty_state() >= 0) {
-		spin_lock(&lru_list_lock);
-		if (write_some_buffers(NULL) == 0)
-			break;
-	}
-	clear_bit(0, (unsigned long *)pexclude);
+	BUG_ON(!list_empty(&bh->b_inode_buffers));
+	mempool_free(bh, bh_mempool);
 }
+EXPORT_SYMBOL(free_buffer_head);
 
-void wakeup_bdflush(void)
+static void init_buffer_head(void *data, kmem_cache_t *cachep, unsigned long flags)
 {
-	static unsigned long exclude;
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+			    SLAB_CTOR_CONSTRUCTOR) {
+		struct buffer_head * bh = (struct buffer_head *)data;
 
-	if (!test_and_set_bit(0, &exclude)) {
-		if (pdflush_operation(bdflush, (unsigned long)&exclude))
-			clear_bit(0, &exclude);
+		memset(bh, 0, sizeof(*bh));
+		bh->b_blocknr = -1;
+		INIT_LIST_HEAD(&bh->b_inode_buffers);
 	}
 }
 
-/*
- * kupdate
- */
-static struct timer_list kupdate_timer;
-static void kupdate_handler(unsigned long dummy)
+static void *bh_mempool_alloc(int gfp_mask, void *pool_data)
 {
-	pdflush_operation(sync_old_buffers, 0);
-	mod_timer(&kupdate_timer, jiffies + bdf_prm.b_un.interval);
+	return kmem_cache_alloc(bh_cachep, gfp_mask);
 }
 
-static int __init kupdate_init(void)
+static void bh_mempool_free(void *element, void *pool_data)
 {
-	init_timer(&kupdate_timer);
-	kupdate_timer.expires = jiffies + bdf_prm.b_un.interval;
-	kupdate_timer.data = 0;
-	kupdate_timer.function = kupdate_handler;
-	add_timer(&kupdate_timer);
-	return 0;
+	return kmem_cache_free(bh_cachep, element);
 }
 
-module_init(kupdate_init)
+#define NR_RESERVED (10*MAX_BUF_PER_PAGE)
+#define MAX_UNUSED_BUFFERS NR_RESERVED+20
 
+void __init buffer_init(void)
+{
+	int i;
+
+	bh_cachep = kmem_cache_create("buffer_head",
+			sizeof(struct buffer_head), 0,
+			SLAB_HWCACHE_ALIGN, init_buffer_head, NULL);
+	bh_mempool = mempool_create(MAX_UNUSED_BUFFERS, bh_mempool_alloc,
+				bh_mempool_free, NULL);
+	for (i = 0; i < ARRAY_SIZE(bh_wait_queue_heads); i++)
+		init_waitqueue_head(&bh_wait_queue_heads[i].wqh);
+}
diff -Nru a/fs/coda/symlink.c b/fs/coda/symlink.c
--- a/fs/coda/symlink.c	Tue Apr 30 17:10:25 2002
+++ b/fs/coda/symlink.c	Tue Apr 30 17:10:25 2002
@@ -40,13 +40,13 @@
 		goto fail;
 	SetPageUptodate(page);
 	kunmap(page);
-	UnlockPage(page);
+	unlock_page(page);
 	return 0;
 
 fail:
 	SetPageError(page);
 	kunmap(page);
-	UnlockPage(page);
+	unlock_page(page);
 	return error;
 }
 
diff -Nru a/fs/cramfs/inode.c b/fs/cramfs/inode.c
--- a/fs/cramfs/inode.c	Tue Apr 30 17:10:23 2002
+++ b/fs/cramfs/inode.c	Tue Apr 30 17:10:23 2002
@@ -293,6 +293,8 @@
 	if (offset & 3)
 		return -EINVAL;
 
+	lock_kernel();
+
 	copied = 0;
 	while (offset < inode->i_size) {
 		struct cramfs_inode *de;
@@ -313,8 +315,10 @@
 		namelen = de->namelen << 2;
 		nextoffset = offset + sizeof(*de) + namelen;
 		for (;;) {
-			if (!namelen)
+			if (!namelen) {
+				unlock_kernel();
 				return -EIO;
+			}
 			if (name[namelen-1])
 				break;
 			namelen--;
@@ -327,6 +331,7 @@
 		filp->f_pos = offset;
 		copied++;
 	}
+	unlock_kernel();
 	return 0;
 }
 
@@ -425,7 +430,7 @@
 	kunmap(page);
 	flush_dcache_page(page);
 	SetPageUptodate(page);
-	UnlockPage(page);
+	unlock_page(page);
 	return 0;
 }
 
diff -Nru a/fs/dcache.c b/fs/dcache.c
--- a/fs/dcache.c	Tue Apr 30 17:10:23 2002
+++ b/fs/dcache.c	Tue Apr 30 17:10:23 2002
@@ -849,6 +849,8 @@
 	struct dentry * dentry;
 	spin_lock(&dcache_lock);
 	dentry = __d_lookup(parent,name);
+	if (dentry)
+		__dget_locked(dentry);
 	spin_unlock(&dcache_lock);
 	return dentry;
 }
@@ -881,7 +883,6 @@
 			if (memcmp(dentry->d_name.name, str, len))
 				continue;
 		}
-		__dget_locked(dentry);
 		dentry->d_vfs_flags |= DCACHE_REFERENCED;
 		return dentry;
 	}
@@ -1385,18 +1386,6 @@
 	} while (i);
 }
 
-static void init_buffer_head(void * foo, kmem_cache_t * cachep, unsigned long flags)
-{
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR)
-	{
-		struct buffer_head * bh = (struct buffer_head *) foo;
-
-		memset(bh, 0, sizeof(*bh));
-		init_waitqueue_head(&bh->b_wait);
-	}
-}
-
 /* SLAB cache for __getname() consumers */
 kmem_cache_t *names_cachep;
 
@@ -1406,9 +1395,6 @@
 /* SLAB cache for dquot structures */
 kmem_cache_t *dquot_cachep;
 
-/* SLAB cache for buffer_head structures */
-kmem_cache_t *bh_cachep;
-EXPORT_SYMBOL(bh_cachep);
 EXPORT_SYMBOL(d_genocide);
 
 extern void bdev_cache_init(void);
@@ -1416,12 +1402,6 @@
 
 void __init vfs_caches_init(unsigned long mempages)
 {
-	bh_cachep = kmem_cache_create("buffer_head",
-			sizeof(struct buffer_head), 0,
-			SLAB_HWCACHE_ALIGN, init_buffer_head, NULL);
-	if(!bh_cachep)
-		panic("Cannot create buffer head SLAB cache");
-
 	names_cachep = kmem_cache_create("names_cache", 
 			PATH_MAX, 0, 
 			SLAB_HWCACHE_ALIGN, NULL, NULL);
diff -Nru a/fs/devpts/root.c b/fs/devpts/root.c
--- a/fs/devpts/root.c	Tue Apr 30 17:10:23 2002
+++ b/fs/devpts/root.c	Tue Apr 30 17:10:23 2002
@@ -48,18 +48,20 @@
 	off_t nr;
 	char numbuf[16];
 
+	lock_kernel();
+
 	nr = filp->f_pos;
 
 	switch(nr)
 	{
 	case 0:
 		if (filldir(dirent, ".", 1, nr, inode->i_ino, DT_DIR) < 0)
-			return 0;
+			goto out;
 		filp->f_pos = ++nr;
 		/* fall through */
 	case 1:
 		if (filldir(dirent, "..", 2, nr, inode->i_ino, DT_DIR) < 0)
-			return 0;
+			goto out;
 		filp->f_pos = ++nr;
 		/* fall through */
 	default:
@@ -68,13 +70,15 @@
 			if ( sbi->inodes[ptynr] ) {
 				genptsname(numbuf, ptynr);
 				if ( filldir(dirent, numbuf, strlen(numbuf), nr, nr, DT_CHR) < 0 )
-					return 0;
+					goto out;
 			}
 			filp->f_pos = ++nr;
 		}
 		break;
 	}
 
+out:
+	unlock_kernel();
 	return 0;
 }
 
diff -Nru a/fs/efs/dir.c b/fs/efs/dir.c
--- a/fs/efs/dir.c	Tue Apr 30 17:10:25 2002
+++ b/fs/efs/dir.c	Tue Apr 30 17:10:25 2002
@@ -5,6 +5,7 @@
  */
 
 #include <linux/efs_fs.h>
+#include <linux/smp_lock.h>
 
 static int efs_readdir(struct file *, void *, filldir_t);
 
@@ -31,6 +32,8 @@
 	if (inode->i_size & (EFS_DIRBSIZE-1))
 		printk(KERN_WARNING "EFS: WARNING: readdir(): directory size not a multiple of EFS_DIRBSIZE\n");
 
+	lock_kernel();
+
 	/* work out where this entry can be found */
 	block = filp->f_pos >> EFS_DIRBSIZE_BITS;
 
@@ -91,7 +94,7 @@
 				}
 				brelse(bh);
 				filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot;
-				return 0;
+				goto out;
 			}
 			slot++;
 		}
@@ -102,6 +105,8 @@
 	}
 
 	filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot;
+out:
+	unlock_kernel();
 	return 0;
 }
 
diff -Nru a/fs/efs/symlink.c b/fs/efs/symlink.c
--- a/fs/efs/symlink.c	Tue Apr 30 17:10:25 2002
+++ b/fs/efs/symlink.c	Tue Apr 30 17:10:25 2002
@@ -42,13 +42,13 @@
 	unlock_kernel();
 	SetPageUptodate(page);
 	kunmap(page);
-	UnlockPage(page);
+	unlock_page(page);
 	return 0;
 fail:
 	unlock_kernel();
 	SetPageError(page);
 	kunmap(page);
-	UnlockPage(page);
+	unlock_page(page);
 	return err;
 }
 
diff -Nru a/fs/ext2/dir.c b/fs/ext2/dir.c
--- a/fs/ext2/dir.c	Tue Apr 30 17:10:23 2002
+++ b/fs/ext2/dir.c	Tue Apr 30 17:10:23 2002
@@ -23,6 +23,7 @@
 
 #include "ext2.h"
 #include <linux/pagemap.h>
+#include <linux/smp_lock.h>
 
 typedef struct ext2_dir_entry_2 ext2_dirent;
 
@@ -46,19 +47,31 @@
 	return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT;
 }
 
+/*
+ * Return the offset into page `page_nr' of the last valid
+ * byte in that page, plus one.
+ */
+static unsigned
+ext2_last_byte(struct inode *inode, unsigned long page_nr)
+{
+	unsigned last_byte = inode->i_size;
+
+	last_byte -= page_nr << PAGE_CACHE_SHIFT;
+	if (last_byte > PAGE_CACHE_SIZE)
+		last_byte = PAGE_CACHE_SIZE;
+	return last_byte;
+}
+
 static int ext2_commit_chunk(struct page *page, unsigned from, unsigned to)
 {
 	struct inode *dir = page->mapping->host;
 	int err = 0;
 	dir->i_version = ++event;
 	page->mapping->a_ops->commit_write(NULL, page, from, to);
-	if (IS_SYNC(dir)) {
-		int err2;
-		err = writeout_one_page(page);
-		err2 = waitfor_one_page(page);
-		if (err == 0)
-			err = err2;
-	}
+	if (IS_SYNC(dir))
+		err = write_one_page(page, 1);
+	else
+		unlock_page(page);
 	return err;
 }
 
@@ -78,10 +91,6 @@
 		limit = dir->i_size & ~PAGE_CACHE_MASK;
 		if (limit & (chunk_size - 1))
 			goto Ebadsize;
-		for (offs = limit; offs<PAGE_CACHE_SIZE; offs += chunk_size) {
-			ext2_dirent *p = (ext2_dirent*)(kaddr + offs);
-			p->rec_len = cpu_to_le16(chunk_size);
-		}
 		if (!limit)
 			goto out;
 	}
@@ -153,9 +162,9 @@
 	struct page *page = read_cache_page(mapping, n,
 				(filler_t*)mapping->a_ops->readpage, NULL);
 	if (!IS_ERR(page)) {
-		wait_on_page(page);
+		wait_on_page_locked(page);
 		kmap(page);
-		if (!Page_Uptodate(page))
+		if (!PageUptodate(page))
 			goto fail;
 		if (!PageChecked(page))
 			ext2_check_page(page);
@@ -197,8 +206,11 @@
 {
 	ext2_dirent *de = (ext2_dirent*)(base + offset);
 	ext2_dirent *p = (ext2_dirent*)(base + (offset&mask));
-	while ((char*)p < (char*)de)
+	while ((char*)p < (char*)de) {
+		if (p->rec_len == 0)
+			break;
 		p = ext2_next_entry(p);
+	}
 	return (char *)p - base;
 }
 
@@ -245,6 +257,9 @@
 	unsigned chunk_mask = ~(ext2_chunk_size(inode)-1);
 	unsigned char *types = NULL;
 	int need_revalidate = (filp->f_version != inode->i_version);
+	int ret = 0;
+
+	lock_kernel();
 
 	if (pos > inode->i_size - EXT2_DIR_REC_LEN(1))
 		goto done;
@@ -265,8 +280,15 @@
 			need_revalidate = 0;
 		}
 		de = (ext2_dirent *)(kaddr+offset);
-		limit = kaddr + PAGE_CACHE_SIZE - EXT2_DIR_REC_LEN(1);
-		for ( ;(char*)de <= limit; de = ext2_next_entry(de))
+		limit = kaddr + ext2_last_byte(inode, n) - EXT2_DIR_REC_LEN(1);
+		for ( ;(char*)de <= limit; de = ext2_next_entry(de)) {
+			if (de->rec_len == 0) {
+				ext2_error(sb, __FUNCTION__,
+					"zero-length directory entry");
+				ret = -EIO;
+				ext2_put_page(page);
+				goto done;
+			}
 			if (de->inode) {
 				int over;
 				unsigned char d_type = DT_UNKNOWN;
@@ -283,6 +305,7 @@
 					goto done;
 				}
 			}
+		}
 		ext2_put_page(page);
 	}
 
@@ -290,6 +313,7 @@
 	filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset;
 	filp->f_version = inode->i_version;
 	UPDATE_ATIME(inode);
+	unlock_kernel();
 	return 0;
 }
 
@@ -326,8 +350,14 @@
 		if (!IS_ERR(page)) {
 			kaddr = page_address(page);
 			de = (ext2_dirent *) kaddr;
-			kaddr += PAGE_CACHE_SIZE - reclen;
+			kaddr += ext2_last_byte(dir, n) - reclen;
 			while ((char *) de <= kaddr) {
+				if (de->rec_len == 0) {
+					ext2_error(dir->i_sb, __FUNCTION__,
+						"zero-length directory entry");
+					ext2_put_page(page);
+					goto out;
+				}
 				if (ext2_match (namelen, name, de))
 					goto found;
 				de = ext2_next_entry(de);
@@ -337,6 +367,7 @@
 		if (++n >= npages)
 			n = 0;
 	} while (n != start);
+out:
 	return NULL;
 
 found:
@@ -387,7 +418,6 @@
 	de->inode = cpu_to_le32(inode->i_ino);
 	ext2_set_de_type (de, inode);
 	err = ext2_commit_chunk(page, from, to);
-	UnlockPage(page);
 	ext2_put_page(page);
 	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
 	mark_inode_dirty(dir);
@@ -401,6 +431,7 @@
 	struct inode *dir = dentry->d_parent->d_inode;
 	const char *name = dentry->d_name.name;
 	int namelen = dentry->d_name.len;
+	unsigned chunk_size = ext2_chunk_size(dir);
 	unsigned reclen = EXT2_DIR_REC_LEN(namelen);
 	unsigned short rec_len, name_len;
 	struct page *page = NULL;
@@ -411,19 +442,41 @@
 	unsigned from, to;
 	int err;
 
-	/* We take care of directory expansion in the same loop */
+	/*
+	 * We take care of directory expansion in the same loop.
+	 * This code plays outside i_size, so it locks the page
+	 * to protect that region.
+	 */
 	for (n = 0; n <= npages; n++) {
+		char *dir_end;
+
 		page = ext2_get_page(dir, n);
 		err = PTR_ERR(page);
 		if (IS_ERR(page))
 			goto out;
+		lock_page(page);
 		kaddr = page_address(page);
+		dir_end = kaddr + ext2_last_byte(dir, n);
 		de = (ext2_dirent *)kaddr;
 		kaddr += PAGE_CACHE_SIZE - reclen;
 		while ((char *)de <= kaddr) {
+			if ((char *)de == dir_end) {
+				/* We hit i_size */
+				name_len = 0;
+				rec_len = chunk_size;
+				de->rec_len = cpu_to_le16(chunk_size);
+				de->inode = 0;
+				goto got_it;
+			}
+			if (de->rec_len == 0) {
+				ext2_error(dir->i_sb, __FUNCTION__,
+					"zero-length directory entry");
+				err = -EIO;
+				goto out_unlock;
+			}
 			err = -EEXIST;
 			if (ext2_match (namelen, name, de))
-				goto out_page;
+				goto out_unlock;
 			name_len = EXT2_DIR_REC_LEN(de->name_len);
 			rec_len = le16_to_cpu(de->rec_len);
 			if (!de->inode && rec_len >= reclen)
@@ -432,6 +485,7 @@
 				goto got_it;
 			de = (ext2_dirent *) ((char *) de + rec_len);
 		}
+		unlock_page(page);
 		ext2_put_page(page);
 	}
 	BUG();
@@ -440,7 +494,6 @@
 got_it:
 	from = (char*)de - (char*)page_address(page);
 	to = from + rec_len;
-	lock_page(page);
 	err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
 	if (err)
 		goto out_unlock;
@@ -458,12 +511,13 @@
 	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
 	mark_inode_dirty(dir);
 	/* OFFSET_CACHE */
-out_unlock:
-	UnlockPage(page);
-out_page:
+out_put:
 	ext2_put_page(page);
 out:
 	return err;
+out_unlock:
+	unlock_page(page);
+	goto out_put;
 }
 
 /*
@@ -482,6 +536,12 @@
 	int err;
 
 	while ((char*)de < (char*)dir) {
+		if (de->rec_len == 0) {
+			ext2_error(inode->i_sb, __FUNCTION__,
+				"zero-length directory entry");
+			err = -EIO;
+			goto out;
+		}
 		pde = de;
 		de = ext2_next_entry(de);
 	}
@@ -495,10 +555,10 @@
 		pde->rec_len = cpu_to_le16(to-from);
 	dir->inode = 0;
 	err = ext2_commit_chunk(page, from, to);
-	UnlockPage(page);
-	ext2_put_page(page);
 	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
 	mark_inode_dirty(inode);
+out:
+	ext2_put_page(page);
 	return err;
 }
 
@@ -517,9 +577,10 @@
 	if (!page)
 		return -ENOMEM;
 	err = mapping->a_ops->prepare_write(NULL, page, 0, chunk_size);
-	if (err)
+	if (err) {
+		unlock_page(page);
 		goto fail;
-
+	}
 	base = page_address(page);
 
 	de = (struct ext2_dir_entry_2 *) base;
@@ -538,7 +599,6 @@
 
 	err = ext2_commit_chunk(page, 0, chunk_size);
 fail:
-	UnlockPage(page);
 	page_cache_release(page);
 	return err;
 }
@@ -550,7 +610,7 @@
 {
 	struct page *page = NULL;
 	unsigned long i, npages = dir_pages(inode);
-	
+
 	for (i = 0; i < npages; i++) {
 		char *kaddr;
 		ext2_dirent * de;
@@ -561,9 +621,15 @@
 
 		kaddr = page_address(page);
 		de = (ext2_dirent *)kaddr;
-		kaddr += PAGE_CACHE_SIZE-EXT2_DIR_REC_LEN(1);
+		kaddr += ext2_last_byte(inode, i) - EXT2_DIR_REC_LEN(1);
 
 		while ((char *)de <= kaddr) {
+			if (de->rec_len == 0) {
+				ext2_error(inode->i_sb, __FUNCTION__,
+					"zero-length directory entry");
+				printk("kaddr=%p, de=%p\n", kaddr, de);
+				goto not_empty;
+			}
 			if (de->inode != 0) {
 				/* check for . and .. */
 				if (de->name[0] != '.')
diff -Nru a/fs/ext2/fsync.c b/fs/ext2/fsync.c
--- a/fs/ext2/fsync.c	Tue Apr 30 17:10:25 2002
+++ b/fs/ext2/fsync.c	Tue Apr 30 17:10:25 2002
@@ -38,7 +38,6 @@
 	int err;
 	
 	err  = fsync_inode_buffers(inode);
-	err |= fsync_inode_data_buffers(inode);
 	if (!(inode->i_state & I_DIRTY))
 		return err;
 	if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
diff -Nru a/fs/ext2/inode.c b/fs/ext2/inode.c
--- a/fs/ext2/inode.c	Tue Apr 30 17:10:23 2002
+++ b/fs/ext2/inode.c	Tue Apr 30 17:10:23 2002
@@ -403,7 +403,7 @@
 		branch[n].bh = bh;
 		branch[n].p = (u32*) bh->b_data + offsets[n];
 		*branch[n].p = branch[n].key;
-		mark_buffer_uptodate(bh, 1);
+		set_buffer_uptodate(bh);
 		unlock_buffer(bh);
 		mark_buffer_dirty_inode(bh, inode);
 		/* We used to sync bh here if IS_SYNC(inode).
@@ -552,7 +552,7 @@
 	if (ext2_splice_branch(inode, iblock, chain, partial, left) < 0)
 		goto changed;
 
-	bh_result->b_state |= (1UL << BH_New);
+	set_buffer_new(bh_result);
 	goto got_it;
 
 changed:
diff -Nru a/fs/ext3/dir.c b/fs/ext3/dir.c
--- a/fs/ext3/dir.c	Tue Apr 30 17:10:25 2002
+++ b/fs/ext3/dir.c	Tue Apr 30 17:10:25 2002
@@ -21,6 +21,7 @@
 #include <linux/fs.h>
 #include <linux/jbd.h>
 #include <linux/ext3_fs.h>
+#include <linux/smp_lock.h>
 
 static unsigned char ext3_filetype_table[] = {
 	DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
@@ -30,7 +31,7 @@
 
 struct file_operations ext3_dir_operations = {
 	read:		generic_read_dir,
-	readdir:	ext3_readdir,		/* BKL held */
+	readdir:	ext3_readdir,		/* we take BKL. needed?*/
 	ioctl:		ext3_ioctl,		/* BKL held */
 	fsync:		ext3_sync_file,		/* BKL held */
 };
@@ -77,6 +78,8 @@
 	int err;
 	struct inode *inode = filp->f_dentry->d_inode;
 
+	lock_kernel();
+
 	sb = inode->i_sb;
 
 	stored = 0;
@@ -150,6 +153,7 @@
 				filp->f_pos = (filp->f_pos |
 						(sb->s_blocksize - 1)) + 1;
 				brelse (bh);
+				unlock_kernel();
 				return stored;
 			}
 			offset += le16_to_cpu(de->rec_len);
@@ -186,5 +190,6 @@
 		brelse (bh);
 	}
 	UPDATE_ATIME(inode);
+	unlock_kernel();
 	return 0;
 }
diff -Nru a/fs/ext3/fsync.c b/fs/ext3/fsync.c
--- a/fs/ext3/fsync.c	Tue Apr 30 17:10:25 2002
+++ b/fs/ext3/fsync.c	Tue Apr 30 17:10:25 2002
@@ -62,8 +62,6 @@
 	 * we'll end up waiting on them in commit.
 	 */
 	ret = fsync_inode_buffers(inode);
-	ret |= fsync_inode_data_buffers(inode);
-
 	ext3_force_commit(inode->i_sb);
 
 	return ret;
diff -Nru a/fs/ext3/inode.c b/fs/ext3/inode.c
--- a/fs/ext3/inode.c	Tue Apr 30 17:10:25 2002
+++ b/fs/ext3/inode.c	Tue Apr 30 17:10:25 2002
@@ -575,7 +575,7 @@
 			branch[n].p = (u32*) bh->b_data + offsets[n];
 			*branch[n].p = branch[n].key;
 			BUFFER_TRACE(bh, "marking uptodate");
-			mark_buffer_uptodate(bh, 1);
+			set_buffer_uptodate(bh);
 			unlock_buffer(bh);
 
 			BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
@@ -746,7 +746,7 @@
 
 	/* Simplest case - block found, no allocation needed */
 	if (!partial) {
-		bh_result->b_state &= ~(1UL << BH_New);
+		clear_buffer_new(bh_result);
 got_it:
 		map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key));
 		/* Clean up and exit */
@@ -812,7 +812,7 @@
 	if (new_size > ei->i_disksize)
 		ei->i_disksize = new_size;
 
-	bh_result->b_state |= (1UL << BH_New);
+	set_buffer_new(bh_result);
 	goto got_it;
 
 changed:
@@ -874,7 +874,7 @@
 			if (!fatal) {
 				memset(bh->b_data, 0,
 				       inode->i_sb->s_blocksize);
-				mark_buffer_uptodate(bh, 1);
+				set_buffer_uptodate(bh);
 			}
 			unlock_buffer(bh);
 			BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
@@ -1070,7 +1070,7 @@
 /* For commit_write() in data=journal mode */
 static int commit_write_fn(handle_t *handle, struct buffer_head *bh)
 {
-	set_bit(BH_Uptodate, &bh->b_state);
+	set_buffer_uptodate(bh);
 	return ext3_journal_dirty_metadata(handle, bh);
 }
 
@@ -1290,8 +1290,13 @@
 
 	/* bget() all the buffers */
 	if (order_data) {
-		if (!page_has_buffers(page))
-			create_empty_buffers(page, inode->i_sb->s_blocksize);
+		if (!page_has_buffers(page)) {
+			if (!PageUptodate(page))
+				buffer_error();
+			create_empty_buffers(page,
+				inode->i_sb->s_blocksize,
+				(1 << BH_Dirty)|(1 << BH_Uptodate));
+		}
 		page_bufs = page_buffers(page);
 		walk_page_buffers(handle, page_bufs, 0,
 				PAGE_CACHE_SIZE, NULL, bget_one);
@@ -1327,7 +1332,7 @@
 	
 	unlock_kernel();
 	SetPageDirty(page);
-	UnlockPage(page);
+	unlock_page(page);
 	return ret;
 }
 
@@ -1394,7 +1399,7 @@
 		goto out;
 
 	if (!page_has_buffers(page))
-		create_empty_buffers(page, blocksize);
+		create_empty_buffers(page, blocksize, 0);
 
 	/* Find the buffer that contains "offset" */
 	bh = page_buffers(page);
@@ -1417,8 +1422,8 @@
 	}
 
 	/* Ok, it's mapped. Make sure it's up-to-date */
-	if (Page_Uptodate(page))
-		set_bit(BH_Uptodate, &bh->b_state);
+	if (PageUptodate(page))
+		set_buffer_uptodate(bh);
 
 	if (!buffer_uptodate(bh)) {
 		err = -EIO;
@@ -1448,11 +1453,11 @@
 	} else {
 		if (ext3_should_order_data(inode))
 			err = ext3_journal_dirty_data(handle, bh, 0);
-		__mark_buffer_dirty(bh);
+		mark_buffer_dirty(bh);
 	}
 
 unlock:
-	UnlockPage(page);
+	unlock_page(page);
 	page_cache_release(page);
 out:
 	return err;
diff -Nru a/fs/ext3/super.c b/fs/ext3/super.c
--- a/fs/ext3/super.c	Tue Apr 30 17:10:25 2002
+++ b/fs/ext3/super.c	Tue Apr 30 17:10:25 2002
@@ -438,7 +438,7 @@
 		 * floating about in memory - the physical journal device may
 		 * hotswapped, and it breaks the `ro-after' testing code.
 		 */
-		fsync_no_super(sbi->journal_bdev);
+		sync_blockdev(sbi->journal_bdev);
 		invalidate_bdev(sbi->journal_bdev, 0);
 		ext3_blkdev_remove(sbi);
 	}
diff -Nru a/fs/fat/buffer.c b/fs/fat/buffer.c
--- a/fs/fat/buffer.c	Tue Apr 30 17:10:25 2002
+++ b/fs/fat/buffer.c	Tue Apr 30 17:10:25 2002
@@ -75,7 +75,10 @@
 	struct buffer_head *bh,
 	int val)
 {
-	mark_buffer_uptodate(bh, val);
+	if (val)
+		set_buffer_uptodate(bh);
+	else
+		clear_buffer_uptodate(bh);
 }
 
 int default_fat_is_uptodate (struct super_block *sb, struct buffer_head *bh)
diff -Nru a/fs/fat/dir.c b/fs/fat/dir.c
--- a/fs/fat/dir.c	Tue Apr 30 17:10:23 2002
+++ b/fs/fat/dir.c	Tue Apr 30 17:10:23 2002
@@ -17,6 +17,7 @@
 #include <linux/time.h>
 #include <linux/msdos_fs.h>
 #include <linux/dirent.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 
@@ -363,13 +364,16 @@
 	unsigned short opt_shortname = MSDOS_SB(sb)->options.shortname;
 	int ino, inum, chi, chl, i, i2, j, last, last_u, dotoffset = 0;
 	loff_t cpos;
+	int ret = 0;
+	
+	lock_kernel();
 
 	cpos = filp->f_pos;
 /* Fake . and .. for the root directory. */
 	if (inode->i_ino == MSDOS_ROOT_INO) {
 		while (cpos < 2) {
 			if (filldir(dirent, "..", cpos+1, cpos, MSDOS_ROOT_INO, DT_DIR) < 0)
-				return 0;
+				goto out;
 			cpos++;
 			filp->f_pos++;
 		}
@@ -379,8 +383,10 @@
 			cpos = 0;
 		}
 	}
-	if (cpos & (sizeof(struct msdos_dir_entry)-1))
-		return -ENOENT;
+	if (cpos & (sizeof(struct msdos_dir_entry)-1)) {
+		ret = -ENOENT;
+		goto out;
+	}
 
  	bh = NULL;
 GetNew:
@@ -414,7 +420,8 @@
 			if (!unicode) {
 				filp->f_pos = cpos;
 				fat_brelse(sb, bh);
-				return -ENOMEM;
+				ret = -ENOMEM;
+				goto out;
 			}
 		}
 ParseLong:
@@ -580,7 +587,9 @@
 	if (unicode) {
 		free_page((unsigned long) unicode);
 	}
-	return 0;
+out:
+	unlock_kernel();
+	return ret;
 }
 
 int fat_readdir(struct file *filp, void *dirent, filldir_t filldir)
diff -Nru a/fs/fat/file.c b/fs/fat/file.c
--- a/fs/fat/file.c	Tue Apr 30 17:10:25 2002
+++ b/fs/fat/file.c	Tue Apr 30 17:10:25 2002
@@ -71,7 +71,7 @@
 		return phys;
 	if (!phys)
 		BUG();
-	bh_result->b_state |= (1UL << BH_New);
+	set_buffer_new(bh_result);
 	map_bh(bh_result, sb, phys);
 	return 0;
 }
diff -Nru a/fs/freevxfs/vxfs_immed.c b/fs/freevxfs/vxfs_immed.c
--- a/fs/freevxfs/vxfs_immed.c	Tue Apr 30 17:10:23 2002
+++ b/fs/freevxfs/vxfs_immed.c	Tue Apr 30 17:10:23 2002
@@ -132,7 +132,7 @@
 	
 	flush_dcache_page(pp);
 	SetPageUptodate(pp);
-        UnlockPage(pp);
+        unlock_page(pp);
 
 	return 0;
 }
diff -Nru a/fs/freevxfs/vxfs_lookup.c b/fs/freevxfs/vxfs_lookup.c
--- a/fs/freevxfs/vxfs_lookup.c	Tue Apr 30 17:10:25 2002
+++ b/fs/freevxfs/vxfs_lookup.c	Tue Apr 30 17:10:25 2002
@@ -262,8 +262,10 @@
 
 	pos = fp->f_pos - 2;
 	
-	if (pos > VXFS_DIRROUND(ip->i_size))
+	if (pos > VXFS_DIRROUND(ip->i_size)) {
+		unlock_kernel();
 		return 0;
+	}
 
 	npages = dir_pages(ip);
 	nblocks = dir_blocks(ip);
@@ -322,5 +324,6 @@
 done:
 	fp->f_pos = ((page << PAGE_CACHE_SHIFT) | offset) + 2;
 out:
+	unlock_kernel();
 	return 0;
 }
diff -Nru a/fs/freevxfs/vxfs_subr.c b/fs/freevxfs/vxfs_subr.c
--- a/fs/freevxfs/vxfs_subr.c	Tue Apr 30 17:10:25 2002
+++ b/fs/freevxfs/vxfs_subr.c	Tue Apr 30 17:10:25 2002
@@ -71,9 +71,9 @@
 			(filler_t*)mapping->a_ops->readpage, NULL);
 
 	if (!IS_ERR(pp)) {
-		wait_on_page(pp);
+		wait_on_page_locked(pp);
 		kmap(pp);
-		if (!Page_Uptodate(pp))
+		if (!PageUptodate(pp))
 			goto fail;
 		/** if (!PageChecked(pp)) **/
 			/** vxfs_check_page(pp); **/
diff -Nru a/fs/fs-writeback.c b/fs/fs-writeback.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/fs-writeback.c	Tue Apr 30 17:10:25 2002
@@ -0,0 +1,522 @@
+/*
+ * fs/fs-writeback.c
+ *
+ * Copyright (C) 2002, Linus Torvalds.
+ *
+ * Contains all the functions related to writing back and waiting
+ * upon dirty inodes against superblocks, and writing back dirty
+ * pages against inodes.  ie: data writeback.  Writeout of the
+ * inode itself is not handled here.
+ *
+ * 10Apr2002	akpm@zip.com.au
+ *		Split out of fs/inode.c
+ *		Additions for address_space-based writeback
+ */
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/writeback.h>
+
+/**
+ *	__mark_inode_dirty -	internal function
+ *	@inode: inode to mark
+ *	@flags: what kind of dirty (i.e. I_DIRTY_SYNC)
+ *	Mark an inode as dirty. Callers should use mark_inode_dirty or
+ *  	mark_inode_dirty_sync.
+ *
+ * Put the inode on the super block's dirty list.
+ *
+ * CAREFUL! We mark it dirty unconditionally, but move it onto the
+ * dirty list only if it is hashed or if it refers to a blockdev.
+ * If it was not hashed, it will never be added to the dirty list
+ * even if it is later hashed, as it will have been marked dirty already.
+ *
+ * In short, make sure you hash any inodes _before_ you start marking
+ * them dirty.
+ *
+ * This function *must* be atomic for the I_DIRTY_PAGES case -
+ * set_page_dirty() is called under spinlock in several places.
+ */
+void __mark_inode_dirty(struct inode *inode, int flags)
+{
+	struct super_block *sb = inode->i_sb;
+
+	if (!sb)
+		return;		/* swapper_space */
+
+	/*
+	 * Don't do this for I_DIRTY_PAGES - that doesn't actually
+	 * dirty the inode itself
+	 */
+	if (flags & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) {
+		if (sb->s_op && sb->s_op->dirty_inode)
+			sb->s_op->dirty_inode(inode);
+	}
+
+	/* avoid the locking if we can */
+	if ((inode->i_state & flags) == flags)
+		return;
+
+	spin_lock(&inode_lock);
+	if ((inode->i_state & flags) != flags) {
+		inode->i_state |= flags;
+
+		/*
+		 * If the inode is locked, just update its dirty state. 
+		 * The unlocker will place the inode on the appropriate
+		 * superblock list, based upon its state.
+		 */
+		if (inode->i_state & I_LOCK)
+			goto same_list;
+
+		/*
+		 * Only add valid (hashed) inode to the superblock's
+		 * dirty list.  Add blockdev inodes as well.
+		 */
+		if (list_empty(&inode->i_hash) && !S_ISBLK(inode->i_mode))
+			goto same_list;
+		if (inode->i_mapping->dirtied_when == 0)
+			inode->i_mapping->dirtied_when = jiffies;
+		list_del(&inode->i_list);
+		list_add(&inode->i_list, &sb->s_dirty);
+	}
+same_list:
+	spin_unlock(&inode_lock);
+}
+
+static inline void write_inode(struct inode *inode, int sync)
+{
+	if (inode->i_sb->s_op && inode->i_sb->s_op->write_inode &&
+			!is_bad_inode(inode))
+		inode->i_sb->s_op->write_inode(inode, sync);
+}
+
+/*
+ * Write a single inode's dirty pages and inode data out to disk.
+ * If `sync' is set, wait on the writeout.
+ * If `nr_to_write' is not NULL, subtract the number of written pages
+ * from *nr_to_write.
+ *
+ * Normally it is not legal for a single process to lock more than one
+ * page at a time, due to ab/ba deadlock problems.  But writeback_mapping()
+ * does want to lock a large number of pages, without immediately submitting
+ * I/O against them (starting I/O is a "deferred unlock_page").
+ *
+ * However it *is* legal to lock multiple pages, if this is only ever performed
+ * by a single process.  We provide that exclusion via locking in the
+ * filesystem's ->writeback_mapping a_op. This ensures that only a single
+ * process is locking multiple pages against this inode.  And as I/O is
+ * submitted against all those locked pages, there is no deadlock.
+ *
+ * Called under inode_lock.
+ */
+static void __sync_single_inode(struct inode *inode, int wait, int *nr_to_write)
+{
+	unsigned dirty;
+	struct address_space *mapping = inode->i_mapping;
+
+	list_del(&inode->i_list);
+	list_add(&inode->i_list, &inode->i_sb->s_locked_inodes);
+
+	if (inode->i_state & I_LOCK)
+		BUG();
+
+	/* Set I_LOCK, reset I_DIRTY */
+	dirty = inode->i_state & I_DIRTY;
+	inode->i_state |= I_LOCK;
+	inode->i_state &= ~I_DIRTY;
+	spin_unlock(&inode_lock);
+
+	if (wait)
+		filemap_fdatawait(mapping);
+
+	if (mapping->a_ops->writeback_mapping)
+		mapping->a_ops->writeback_mapping(mapping, nr_to_write);
+	else
+		filemap_fdatawrite(mapping);
+
+	/* Don't write the inode if only I_DIRTY_PAGES was set */
+	if (dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC))
+		write_inode(inode, wait);
+
+	if (wait)
+		filemap_fdatawait(mapping);
+
+	/*
+	 * For non-blocking writeout (wait == 0), we still
+	 * count the inode as being clean.
+	 */
+	spin_lock(&inode_lock);
+
+	/*
+	 * Did we write back all the pages?
+	 */
+	if (nr_to_write && *nr_to_write == 0) {
+		/*
+		 * Maybe not
+		 */
+		if (!list_empty(&mapping->dirty_pages))	/* No lock needed */
+			inode->i_state |= I_DIRTY_PAGES;
+	}
+
+	inode->i_state &= ~I_LOCK;
+	if (!(inode->i_state & I_FREEING)) {
+		struct list_head *to;
+		if (inode->i_state & I_DIRTY)
+			to = &inode->i_sb->s_dirty;
+		else if (atomic_read(&inode->i_count))
+			to = &inode_in_use;
+		else
+			to = &inode_unused;
+		list_del(&inode->i_list);
+		list_add(&inode->i_list, to);
+	}
+	wake_up(&inode->i_wait);
+}
+
+/*
+ * Write out an inode's dirty pages.  Called under inode_lock.
+ */
+static void
+__writeback_single_inode(struct inode *inode, int sync, int *nr_to_write)
+{
+	while (inode->i_state & I_LOCK) {
+		__iget(inode);
+		spin_unlock(&inode_lock);
+		__wait_on_inode(inode);
+		iput(inode);
+		spin_lock(&inode_lock);
+	}
+	__sync_single_inode(inode, sync, nr_to_write);
+}
+
+void writeback_single_inode(struct inode *inode, int sync, int *nr_to_write)
+{
+	spin_lock(&inode_lock);
+	__writeback_single_inode(inode, sync, nr_to_write);
+	spin_unlock(&inode_lock);
+}
+
+/*
+ * Write out a list of inodes' pages, and the inode itself.
+ *
+ * If `sync' is true, wait on writeout of the last mapping
+ * which we write.
+ *
+ * If older_than_this is non-NULL, then only write out mappings which
+ * had their first dirtying at a time earlier than *older_than_this.
+ *
+ * Called under inode_lock.
+ *
+ * FIXME: putting all the inodes on a local list could introduce a
+ * race with umount.  Bump the superblock refcount?
+ */
+static void __sync_list(struct list_head *head, int sync_mode,
+		int *nr_to_write, unsigned long *older_than_this)
+{
+	struct list_head * tmp;
+	LIST_HEAD(hold);	/* Unready inodes go here */
+
+	while ((tmp = head->next) != head) {
+		struct inode *inode = list_entry(tmp, struct inode, i_list);
+		struct address_space *mapping = inode->i_mapping;
+		int really_sync;
+
+		if (older_than_this && *older_than_this) {
+			if (time_after(mapping->dirtied_when,
+						*older_than_this)) {
+				list_del(&inode->i_list);
+				list_add(&inode->i_list, &hold);
+				continue;
+			}
+		}
+		really_sync = (sync_mode == WB_SYNC_ALL);
+		if ((sync_mode == WB_SYNC_LAST) && (head->prev == head))
+			really_sync = 1;
+		__writeback_single_inode(inode, really_sync, nr_to_write);
+		if (nr_to_write && *nr_to_write == 0)
+			break;
+	}
+	/*
+	 * Put the not-ready inodes back
+	 */
+	if (!list_empty(&hold))
+		list_splice(&hold, head);
+}
+
+/*
+ * Start writeback of dirty pagecache data against all unlocked inodes.
+ *
+ * Note:
+ * We don't need to grab a reference to superblock here. If it has non-empty
+ * ->s_dirty it's hadn't been killed yet and kill_super() won't proceed
+ * past sync_inodes_sb() until both ->s_dirty and ->s_locked_inodes are
+ * empty. Since __sync_single_inode() regains inode_lock before it finally moves
+ * inode from superblock lists we are OK.
+ *
+ * If `older_than_this' is non-zero then only flush inodes which have a
+ * flushtime older than *older_than_this.  Unless *older_than_this is
+ * zero.  In which case we flush everything, like the old (dumb) wakeup_bdflush.
+ */
+void writeback_unlocked_inodes(int *nr_to_write, int sync_mode,
+				unsigned long *older_than_this)
+{
+	struct super_block * sb;
+	static unsigned short writeback_gen;
+
+	spin_lock(&inode_lock);
+	spin_lock(&sb_lock);
+
+	/*
+	 * We could get into livelock here if someone is dirtying
+	 * inodes fast enough.  writeback_gen is used to avoid that.
+	 */
+	writeback_gen++;
+
+	sb = sb_entry(super_blocks.prev);
+	for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.prev)) {
+		if (sb->s_writeback_gen == writeback_gen)
+			continue;
+		sb->s_writeback_gen = writeback_gen;
+
+		if (current->flags & PF_FLUSHER) {
+			if (sb->s_flags & MS_FLUSHING) {
+				/*
+				 * There's no point in two pdflush threads
+				 * flushing the same device.  But for other
+				 * callers, we want to perform the flush
+				 * because the fdatasync is how we implement
+				 * writer throttling.
+				 */
+				continue;
+			}
+			sb->s_flags |= MS_FLUSHING;
+		}
+
+		if (!list_empty(&sb->s_dirty)) {
+			spin_unlock(&sb_lock);
+			__sync_list(&sb->s_dirty, sync_mode,
+					nr_to_write, older_than_this);
+			spin_lock(&sb_lock);
+		}
+		if (current->flags & PF_FLUSHER)
+			sb->s_flags &= ~MS_FLUSHING;
+		if (nr_to_write && *nr_to_write == 0)
+			break;
+	}
+	spin_unlock(&sb_lock);
+	spin_unlock(&inode_lock);
+}
+
+/*
+ * Called under inode_lock
+ */
+static int __try_to_writeback_unused_list(struct list_head *head, int nr_inodes)
+{
+	struct list_head *tmp = head;
+	struct inode *inode;
+
+	while (nr_inodes && (tmp = tmp->prev) != head) {
+		inode = list_entry(tmp, struct inode, i_list);
+
+		if (!atomic_read(&inode->i_count)) {
+			__sync_single_inode(inode, 0, NULL);
+			nr_inodes--;
+
+			/* 
+			 * __sync_single_inode moved the inode to another list,
+			 * so we have to start looking from the list head.
+			 */
+			tmp = head;
+		}
+	}
+
+	return nr_inodes;
+}
+
+static void __wait_on_locked(struct list_head *head)
+{
+	struct list_head * tmp;
+	while ((tmp = head->prev) != head) {
+		struct inode *inode = list_entry(tmp, struct inode, i_list);
+		__iget(inode);
+		spin_unlock(&inode_lock);
+		__wait_on_inode(inode);
+		iput(inode);
+		spin_lock(&inode_lock);
+	}
+}
+
+/*
+ * writeback and wait upon the filesystem's dirty inodes.
+ * We do it in two passes - one to write, and one to wait.
+ */
+void sync_inodes_sb(struct super_block *sb)
+{
+	spin_lock(&inode_lock);
+	while (!list_empty(&sb->s_dirty)||!list_empty(&sb->s_locked_inodes)) {
+		__sync_list(&sb->s_dirty, WB_SYNC_NONE, NULL, NULL);
+		__sync_list(&sb->s_dirty, WB_SYNC_ALL, NULL, NULL);
+		__wait_on_locked(&sb->s_locked_inodes);
+	}
+	spin_unlock(&inode_lock);
+}
+
+/*
+ * writeback the dirty inodes for this filesystem
+ */
+void writeback_inodes_sb(struct super_block *sb)
+{
+	spin_lock(&inode_lock);
+	while (!list_empty(&sb->s_dirty))
+		__sync_list(&sb->s_dirty, WB_SYNC_NONE, NULL, NULL);
+	spin_unlock(&inode_lock);
+}
+
+/*
+ * Find a superblock with inodes that need to be synced
+ */
+
+static struct super_block *get_super_to_sync(void)
+{
+	struct list_head *p;
+restart:
+	spin_lock(&inode_lock);
+	spin_lock(&sb_lock);
+	list_for_each(p, &super_blocks) {
+		struct super_block *s = list_entry(p,struct super_block,s_list);
+		if (list_empty(&s->s_dirty) && list_empty(&s->s_locked_inodes))
+			continue;
+		s->s_count++;
+		spin_unlock(&sb_lock);
+		spin_unlock(&inode_lock);
+		down_read(&s->s_umount);
+		if (!s->s_root) {
+			drop_super(s);
+			goto restart;
+		}
+		return s;
+	}
+	spin_unlock(&sb_lock);
+	spin_unlock(&inode_lock);
+	return NULL;
+}
+
+/**
+ *	sync_inodes
+ *	@dev: device to sync the inodes from.
+ *
+ *	sync_inodes goes through the super block's dirty list, 
+ *	writes them out, waits on the writeout and puts the inodes
+ *	back on the normal list.
+ */
+
+void sync_inodes(void)
+{
+	struct super_block * s;
+	/*
+	 * Search the super_blocks array for the device(s) to sync.
+	 */
+	while ((s = get_super_to_sync()) != NULL) {
+		sync_inodes_sb(s);
+		drop_super(s);
+	}
+}
+
+void try_to_writeback_unused_inodes(unsigned long pexclusive)
+{
+	struct super_block * sb;
+	int nr_inodes = inodes_stat.nr_unused;
+
+	spin_lock(&inode_lock);
+	spin_lock(&sb_lock);
+	sb = sb_entry(super_blocks.next);
+	for (; nr_inodes && sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.next)) {
+		if (list_empty(&sb->s_dirty))
+			continue;
+		spin_unlock(&sb_lock);
+		nr_inodes = __try_to_writeback_unused_list(&sb->s_dirty, nr_inodes);
+		spin_lock(&sb_lock);
+	}
+	spin_unlock(&sb_lock);
+	spin_unlock(&inode_lock);
+	clear_bit(0, (unsigned long *)pexclusive);
+}
+
+/**
+ *	write_inode_now	-	write an inode to disk
+ *	@inode: inode to write to disk
+ *	@sync: whether the write should be synchronous or not
+ *
+ *	This function commits an inode to disk immediately if it is
+ *	dirty. This is primarily needed by knfsd.
+ */
+ 
+void write_inode_now(struct inode *inode, int sync)
+{
+	spin_lock(&inode_lock);
+	__writeback_single_inode(inode, sync, NULL);
+	spin_unlock(&inode_lock);
+	if (sync)
+		wait_on_inode(inode);
+}
+
+/**
+ * generic_osync_inode - flush all dirty data for a given inode to disk
+ * @inode: inode to write
+ * @datasync: if set, don't bother flushing timestamps
+ *
+ * This can be called by file_write functions for files which have the
+ * O_SYNC flag set, to flush dirty writes to disk.  
+ */
+
+int generic_osync_inode(struct inode *inode, int what)
+{
+	int err = 0, err2 = 0, need_write_inode_now = 0;
+	
+	/* 
+	 * WARNING
+	 *
+	 * Currently, the filesystem write path does not pass the
+	 * filp down to the low-level write functions.  Therefore it
+	 * is impossible for (say) __block_commit_write to know if
+	 * the operation is O_SYNC or not.
+	 *
+	 * Ideally, O_SYNC writes would have the filesystem call
+	 * ll_rw_block as it went to kick-start the writes, and we
+	 * could call osync_inode_buffers() here to wait only for
+	 * those IOs which have already been submitted to the device
+	 * driver layer.  As it stands, if we did this we'd not write
+	 * anything to disk since our writes have not been queued by
+	 * this point: they are still on the dirty LRU.
+	 * 
+	 * So, currently we will call fsync_inode_buffers() instead,
+	 * to flush _all_ dirty buffers for this inode to disk on 
+	 * every O_SYNC write, not just the synchronous I/Os.  --sct
+	 */
+
+	if (what & OSYNC_DATA)
+		writeback_single_inode(inode, 0, NULL);
+	if (what & (OSYNC_METADATA|OSYNC_DATA))
+		err = fsync_inode_buffers(inode);
+	if (what & OSYNC_DATA) {
+		err2 = filemap_fdatawrite(inode->i_mapping);
+		if (!err)
+			err = err2;
+	}
+
+	spin_lock(&inode_lock);
+	if ((inode->i_state & I_DIRTY) &&
+	    ((what & OSYNC_INODE) || (inode->i_state & I_DIRTY_DATASYNC)))
+		need_write_inode_now = 1;
+	spin_unlock(&inode_lock);
+
+	if (need_write_inode_now)
+		write_inode_now(inode, 1);
+	else
+		wait_on_inode(inode);
+
+	return err;
+}
diff -Nru a/fs/hfs/dir_cap.c b/fs/hfs/dir_cap.c
--- a/fs/hfs/dir_cap.c	Tue Apr 30 17:10:25 2002
+++ b/fs/hfs/dir_cap.c	Tue Apr 30 17:10:25 2002
@@ -188,6 +188,8 @@
         struct hfs_cat_entry *entry;
 	struct inode *dir = filp->f_dentry->d_inode;
 
+	lock_kernel();
+
 	entry = HFS_I(dir)->entry;
 	type = HFS_ITYPE(dir->i_ino);
 	skip_dirs = (type == HFS_CAP_RDIR);
@@ -195,7 +197,7 @@
 	if (filp->f_pos == 0) {
 		/* Entry 0 is for "." */
 		if (filldir(dirent, DOT->Name, DOT_LEN, 0, dir->i_ino, DT_DIR)) {
-			return 0;
+			goto out;
 		}
 		filp->f_pos = 1;
 	}
@@ -212,7 +214,7 @@
 
 		if (filldir(dirent, DOT_DOT->Name,
 			    DOT_DOT_LEN, 1, ntohl(cnid), DT_DIR)) {
-			return 0;
+			goto out;
 		}
 		filp->f_pos = 2;
 	}
@@ -223,11 +225,11 @@
 
 	    	if (hfs_cat_open(entry, &brec) ||
 	    	    hfs_cat_next(entry, &brec, filp->f_pos - 2, &cnid, &type)) {
-			return 0;
+			goto out;
 		}
 		while (filp->f_pos < (dir->i_size - 3)) {
 			if (hfs_cat_next(entry, &brec, 1, &cnid, &type)) {
-				return 0;
+				goto out;
 			}
 			if (!skip_dirs || (type != HFS_CDR_DIR)) {
 				ino_t ino;
@@ -240,7 +242,7 @@
 				if (filldir(dirent, tmp_name, len,
 					    filp->f_pos, ino, DT_UNKNOWN)) {
 					hfs_cat_close(entry, &brec);
-					return 0;
+					goto out;
 				}
 			}
 			++filp->f_pos;
@@ -256,7 +258,7 @@
 				    DOT_ROOTINFO_LEN, filp->f_pos,
 				    ntohl(entry->cnid) | HFS_CAP_FNDR,
 				    DT_UNKNOWN)) {
-				return 0;
+				goto out;
 			}
 		}
 		++filp->f_pos;
@@ -269,7 +271,7 @@
 				    DOT_FINDERINFO_LEN, filp->f_pos,
 				    ntohl(entry->cnid) | HFS_CAP_FDIR,
 				    DT_UNKNOWN)) {
-				return 0;
+				goto out;
 			}
 		}
 		++filp->f_pos;
@@ -282,12 +284,14 @@
 				    DOT_RESOURCE_LEN, filp->f_pos,
 				    ntohl(entry->cnid) | HFS_CAP_RDIR,
 				    DT_UNKNOWN)) {
-				return 0;
+				goto out;
 			}
 		}
 		++filp->f_pos;
 	}
 
+out:
+	unlock_kernel();
 	return 0;
 }
 
diff -Nru a/fs/hfs/dir_dbl.c b/fs/hfs/dir_dbl.c
--- a/fs/hfs/dir_dbl.c	Tue Apr 30 17:10:25 2002
+++ b/fs/hfs/dir_dbl.c	Tue Apr 30 17:10:25 2002
@@ -182,13 +182,15 @@
         struct hfs_cat_entry *entry;
 	struct inode *dir = filp->f_dentry->d_inode;
 
+	lock_kernel();
+
 	entry = HFS_I(dir)->entry;
 
 	if (filp->f_pos == 0) {
 		/* Entry 0 is for "." */
 		if (filldir(dirent, DOT->Name, DOT_LEN, 0, dir->i_ino,
 			    DT_DIR)) {
-			return 0;
+			goto out;
 		}
 		filp->f_pos = 1;
 	}
@@ -197,7 +199,7 @@
 		/* Entry 1 is for ".." */
 		if (filldir(dirent, DOT_DOT->Name, DOT_DOT_LEN, 1,
 			    hfs_get_hl(entry->key.ParID), DT_DIR)) {
-			return 0;
+			goto out;	
 		}
 		filp->f_pos = 2;
 	}
@@ -209,7 +211,7 @@
 		if (hfs_cat_open(entry, &brec) ||
 		    hfs_cat_next(entry, &brec, (filp->f_pos - 1) >> 1,
 				 &cnid, &type)) {
-			return 0;
+			goto out;
 		}
 
 		while (filp->f_pos < (dir->i_size - 1)) {
@@ -226,7 +228,7 @@
 			} else {
 				if (hfs_cat_next(entry, &brec, 1,
 							&cnid, &type)) {
-					return 0;
+					goto out;
 				}
 				ino = ntohl(cnid);
 				len = hfs_namein(dir, tmp_name,
@@ -236,7 +238,7 @@
 			if (filldir(dirent, tmp_name, len, filp->f_pos, ino,
 				    DT_UNKNOWN)) {
 				hfs_cat_close(entry, &brec);
-				return 0;
+				goto out;
 			}
 			++filp->f_pos;
 		}
@@ -250,12 +252,14 @@
 				    PCNT_ROOTINFO_LEN, filp->f_pos,
 				    ntohl(entry->cnid) | HFS_DBL_HDR,
 				    DT_UNKNOWN)) {
-				return 0;
+				goto out;
 			}
 		}
 		++filp->f_pos;
 	}
 
+out:
+	unlock_kernel();
 	return 0;
 }
 
diff -Nru a/fs/hfs/dir_nat.c b/fs/hfs/dir_nat.c
--- a/fs/hfs/dir_nat.c	Tue Apr 30 17:10:25 2002
+++ b/fs/hfs/dir_nat.c	Tue Apr 30 17:10:25 2002
@@ -188,6 +188,8 @@
         struct hfs_cat_entry *entry;
 	struct inode *dir = filp->f_dentry->d_inode;
 
+	lock_kernel();
+	
 	entry = HFS_I(dir)->entry;
 	type = HFS_ITYPE(dir->i_ino);
 	skip_dirs = (type == HFS_NAT_HDIR);
@@ -196,7 +198,7 @@
 		/* Entry 0 is for "." */
 		if (filldir(dirent, DOT->Name, DOT_LEN, 0, dir->i_ino,
 			    DT_DIR)) {
-			return 0;
+			goto out;
 		}
 		filp->f_pos = 1;
 	}
@@ -213,7 +215,7 @@
 
 		if (filldir(dirent, DOT_DOT->Name,
 			    DOT_DOT_LEN, 1, ntohl(cnid), DT_DIR)) {
-			return 0;
+			goto out;
 		}
 		filp->f_pos = 2;
 	}
@@ -224,11 +226,11 @@
 
 	    	if (hfs_cat_open(entry, &brec) ||
 		    hfs_cat_next(entry, &brec, filp->f_pos - 2, &cnid, &type)) {
-			return 0;
+			goto out;
 		}
 		while (filp->f_pos < (dir->i_size - 2)) {
 			if (hfs_cat_next(entry, &brec, 1, &cnid, &type)) {
-				return 0;
+				goto out;
 			}
 			if (!skip_dirs || (type != HFS_CDR_DIR)) {
 				ino_t ino;
@@ -241,7 +243,7 @@
 				if (filldir(dirent, tmp_name, len,
 					    filp->f_pos, ino, DT_UNKNOWN)) {
 					hfs_cat_close(entry, &brec);
-					return 0;
+					goto out;
 				}
 			}
 			++filp->f_pos;
@@ -256,7 +258,7 @@
 				    DOT_APPLEDOUBLE_LEN, filp->f_pos,
 				    ntohl(entry->cnid) | HFS_NAT_HDIR,
 				    DT_UNKNOWN)) {
-				return 0;
+				goto out;
 			}
 		} else if (type == HFS_NAT_HDIR) {
 			/* In .AppleDouble entry 2 is for ".Parent" */
@@ -264,7 +266,7 @@
 				    DOT_PARENT_LEN, filp->f_pos,
 				    ntohl(entry->cnid) | HFS_NAT_HDR,
 				    DT_UNKNOWN)) {
-				return 0;
+				goto out;
 			}
 		}
 		++filp->f_pos;
@@ -278,12 +280,14 @@
 				    ROOTINFO_LEN, filp->f_pos,
 				    ntohl(entry->cnid) | HFS_NAT_HDR,
 				    DT_UNKNOWN)) {
-				return 0;
+				goto out;
 			}
 		}
 		++filp->f_pos;
 	}
 
+out:
+	unlock_kernel();
 	return 0;
 }
 
diff -Nru a/fs/hfs/file.c b/fs/hfs/file.c
--- a/fs/hfs/file.c	Tue Apr 30 17:10:25 2002
+++ b/fs/hfs/file.c	Tue Apr 30 17:10:25 2002
@@ -114,7 +114,7 @@
 	phys = hfs_extent_map(HFS_I(inode)->fork, iblock, create);
 	if (phys) {
 		if (create)
-			bh_result->b_state |= (1UL << BH_New);
+			set_buffer_new(bh_result);
 		map_bh(bh_result, inode->i_sb, phys);
 		return 0;
 	}
@@ -479,7 +479,7 @@
 		pos += c;
 		written += c;
 		buf += c;
-		mark_buffer_uptodate(bh, 1);
+		set_buffer_uptodate(bh);
 		mark_buffer_dirty(bh);
 		brelse(bh);
 	}
diff -Nru a/fs/hfs/sysdep.c b/fs/hfs/sysdep.c
--- a/fs/hfs/sysdep.c	Tue Apr 30 17:10:25 2002
+++ b/fs/hfs/sysdep.c	Tue Apr 30 17:10:25 2002
@@ -45,7 +45,7 @@
 	} else {
 		tmp = sb_getblk(sys_mdb, block);
 		if (tmp) {
-			mark_buffer_uptodate(tmp, 1);
+			set_buffer_uptodate(tmp);
 		}
 	}
 	if (!tmp) {
diff -Nru a/fs/hpfs/buffer.c b/fs/hpfs/buffer.c
--- a/fs/hpfs/buffer.c	Tue Apr 30 17:10:25 2002
+++ b/fs/hpfs/buffer.c	Tue Apr 30 17:10:25 2002
@@ -180,7 +180,7 @@
 
 	if ((*bhp = bh = sb_getblk(s, secno)) != NULL) {
 		if (!buffer_uptodate(bh)) wait_on_buffer(bh);
-		mark_buffer_uptodate(bh, 1);
+		set_buffer_uptodate(bh);
 		return bh->b_data;
 	} else {
 		printk("HPFS: hpfs_get_sector: getblk failed\n");
diff -Nru a/fs/hpfs/dir.c b/fs/hpfs/dir.c
--- a/fs/hpfs/dir.c	Tue Apr 30 17:10:25 2002
+++ b/fs/hpfs/dir.c	Tue Apr 30 17:10:25 2002
@@ -62,19 +62,26 @@
 	long old_pos;
 	char *tempname;
 	int c1, c2 = 0;
+	int ret = 0;
 
 	if (inode->i_sb->s_hpfs_chk) {
-		if (hpfs_chk_sectors(inode->i_sb, inode->i_ino, 1, "dir_fnode"))
-			return -EFSERROR;
-		if (hpfs_chk_sectors(inode->i_sb, hpfs_inode->i_dno, 4, "dir_dnode"))
-			return -EFSERROR;
+		if (hpfs_chk_sectors(inode->i_sb, inode->i_ino, 1, "dir_fnode")) {
+			ret = -EFSERROR;
+			goto out;
+		}
+		if (hpfs_chk_sectors(inode->i_sb, hpfs_inode->i_dno, 4, "dir_dnode")) {
+			ret = -EFSERROR;
+			goto out;
+		}
 	}
 	if (inode->i_sb->s_hpfs_chk >= 2) {
 		struct buffer_head *bh;
 		struct fnode *fno;
 		int e = 0;
-		if (!(fno = hpfs_map_fnode(inode->i_sb, inode->i_ino, &bh)))
-			return -EIOERROR;
+		if (!(fno = hpfs_map_fnode(inode->i_sb, inode->i_ino, &bh))) {
+			ret = -EIOERROR;
+			goto out;
+		}
 		if (!fno->dirflag) {
 			e = 1;
 			hpfs_error(inode->i_sb, "not a directory, fnode %08x",inode->i_ino);
@@ -84,14 +91,20 @@
 			hpfs_error(inode->i_sb, "corrupted inode: i_dno == %08x, fnode -> dnode == %08x", hpfs_inode->i_dno, fno->u.external[0].disk_secno);
 		}
 		brelse(bh);
-		if (e) return -EFSERROR;
+		if (e) {
+			ret = -EFSERROR;
+			goto out;
+		}
 	}
 	lc = inode->i_sb->s_hpfs_lowercase;
 	if (filp->f_pos == 12) { /* diff -r requires this (note, that diff -r */
 		filp->f_pos = 13; /* also fails on msdos filesystem in 2.0) */
-		return 0;
+		goto out;
+	}
+	if (filp->f_pos == 13) {
+		ret = -ENOENT;
+		goto out;
 	}
-	if (filp->f_pos == 13) return -ENOENT;
 	
 	hpfs_lock_inode(inode);
 	
@@ -103,28 +116,29 @@
 		if (inode->i_sb->s_hpfs_chk)
 			if (hpfs_stop_cycles(inode->i_sb, filp->f_pos, &c1, &c2, "hpfs_readdir")) {
 				hpfs_unlock_inode(inode);
-				return -EFSERROR;
+				ret = -EFSERROR;
+				goto out;
 			}
 		if (filp->f_pos == 12) {
 			hpfs_unlock_inode(inode);
-			return 0;
+			goto out;
 		}
 		if (filp->f_pos == 3 || filp->f_pos == 4 || filp->f_pos == 5) {
 			printk("HPFS: warning: pos==%d\n",(int)filp->f_pos);
 			hpfs_unlock_inode(inode);
-			return 0;
+			goto out;
 		}
 		if (filp->f_pos == 0) {
 			if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino, DT_DIR) < 0) {
 				hpfs_unlock_inode(inode);
-				return 0;
+				goto out;
 			}
 			filp->f_pos = 11;
 		}
 		if (filp->f_pos == 11) {
 			if (filldir(dirent, "..", 2, filp->f_pos, hpfs_inode->i_parent_dir, DT_DIR) < 0) {
 				hpfs_unlock_inode(inode);
-				return 0;
+				goto out;
 			}
 			filp->f_pos = 1;
 		}
@@ -135,12 +149,14 @@
 		}
 			/*if (filp->f_version != inode->i_version) {
 				hpfs_unlock_inode(inode);
-				return -ENOENT;
+				ret = -ENOENT;
+				goto out;
 			}*/	
 			old_pos = filp->f_pos;
 			if (!(de = map_pos_dirent(inode, &filp->f_pos, &qbh))) {
 				hpfs_unlock_inode(inode);
-				return -EIOERROR;
+				ret = -EIOERROR;
+				goto out;
 			}
 			if (de->first || de->last) {
 				if (inode->i_sb->s_hpfs_chk) {
@@ -156,11 +172,14 @@
 				if (tempname != (char *)de->name) kfree(tempname);
 				hpfs_brelse4(&qbh);
 				hpfs_unlock_inode(inode);
-				return 0;
+				goto out;
 			}
 			if (tempname != (char *)de->name) kfree(tempname);
 			hpfs_brelse4(&qbh);
 	}
+out:
+	unlock_kernel();
+	return ret;
 }
 
 /*
diff -Nru a/fs/hpfs/file.c b/fs/hpfs/file.c
--- a/fs/hpfs/file.c	Tue Apr 30 17:10:25 2002
+++ b/fs/hpfs/file.c	Tue Apr 30 17:10:25 2002
@@ -91,7 +91,7 @@
 	}
 	inode->i_blocks++;
 	hpfs_i(inode)->mmu_private += 512;
-	bh_result->b_state |= 1UL << BH_New;
+	set_buffer_new(bh_result);
 	map_bh(bh_result, inode->i_sb, s);
 	return 0;
 }
diff -Nru a/fs/hpfs/namei.c b/fs/hpfs/namei.c
--- a/fs/hpfs/namei.c	Tue Apr 30 17:10:25 2002
+++ b/fs/hpfs/namei.c	Tue Apr 30 17:10:25 2002
@@ -448,14 +448,14 @@
 	unlock_kernel();
 	SetPageUptodate(page);
 	kunmap(page);
-	UnlockPage(page);
+	unlock_page(page);
 	return 0;
 
 fail:
 	unlock_kernel();
 	SetPageError(page);
 	kunmap(page);
-	UnlockPage(page);
+	unlock_page(page);
 	return err;
 }
 	
diff -Nru a/fs/inode.c b/fs/inode.c
--- a/fs/inode.c	Tue Apr 30 17:10:25 2002
+++ b/fs/inode.c	Tue Apr 30 17:10:25 2002
@@ -6,17 +6,12 @@
 
 #include <linux/config.h>
 #include <linux/fs.h>
-#include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/dcache.h>
 #include <linux/init.h>
 #include <linux/quotaops.h>
 #include <linux/slab.h>
-#include <linux/cache.h>
-#include <linux/swap.h>
-#include <linux/swapctl.h>
-#include <linux/prefetch.h>
-#include <linux/locks.h>
+#include <linux/writeback.h>
 
 /*
  * New inode.c implementation.
@@ -55,8 +50,8 @@
  * allowing for low-overhead inode sync() operations.
  */
 
-static LIST_HEAD(inode_in_use);
-static LIST_HEAD(inode_unused);
+LIST_HEAD(inode_in_use);
+LIST_HEAD(inode_unused);
 static struct list_head *inode_hashtable;
 static LIST_HEAD(anon_hash_chain); /* for inodes with NULL i_sb */
 
@@ -66,7 +61,7 @@
  * NOTE! You also have to own the lock if you change
  * the i_state of an inode while it is in use..
  */
-static spinlock_t inode_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t inode_lock = SPIN_LOCK_UNLOCKED;
 
 /*
  * Statistics gathering..
@@ -108,7 +103,11 @@
 		inode->i_data.a_ops = &empty_aops;
 		inode->i_data.host = inode;
 		inode->i_data.gfp_mask = GFP_HIGHUSER;
+		inode->i_data.dirtied_when = 0;
 		inode->i_mapping = &inode->i_data;
+		inode->i_data.ra_pages = &default_ra_pages;
+		if (sb->s_bdev)
+			inode->i_data.ra_pages = sb->s_bdev->bd_inode->i_mapping->ra_pages;
 		memset(&inode->u, 0, sizeof(inode->u));
 	}
 	return inode;
@@ -138,14 +137,15 @@
 	INIT_LIST_HEAD(&inode->i_data.clean_pages);
 	INIT_LIST_HEAD(&inode->i_data.dirty_pages);
 	INIT_LIST_HEAD(&inode->i_data.locked_pages);
+	INIT_LIST_HEAD(&inode->i_data.io_pages);
 	INIT_LIST_HEAD(&inode->i_dentry);
 	INIT_LIST_HEAD(&inode->i_dirty_buffers);
-	INIT_LIST_HEAD(&inode->i_dirty_data_buffers);
 	INIT_LIST_HEAD(&inode->i_devices);
 	sema_init(&inode->i_sem, 1);
 	INIT_RADIX_TREE(&inode->i_data.page_tree, GFP_ATOMIC);
 	rwlock_init(&inode->i_data.page_lock);
 	spin_lock_init(&inode->i_data.i_shared_lock);
+	spin_lock_init(&inode->i_bufferlist_lock);
 	INIT_LIST_HEAD(&inode->i_data.i_mmap);
 	INIT_LIST_HEAD(&inode->i_data.i_mmap_shared);
 }
@@ -159,57 +159,7 @@
 		inode_init_once(inode);
 }
 
-/*
- * Put the inode on the super block's dirty list.
- *
- * CAREFUL! We mark it dirty unconditionally, but
- * move it onto the dirty list only if it is hashed.
- * If it was not hashed, it will never be added to
- * the dirty list even if it is later hashed, as it
- * will have been marked dirty already.
- *
- * In short, make sure you hash any inodes _before_
- * you start marking them dirty..
- */
- 
-/**
- *	__mark_inode_dirty -	internal function
- *	@inode: inode to mark
- *	@flags: what kind of dirty (i.e. I_DIRTY_SYNC)
- *	Mark an inode as dirty. Callers should use mark_inode_dirty or
- *  	mark_inode_dirty_sync.
- */
- 
-void __mark_inode_dirty(struct inode *inode, int flags)
-{
-	struct super_block * sb = inode->i_sb;
-
-	if (!sb)
-		return;
-
-	/* Don't do this for I_DIRTY_PAGES - that doesn't actually dirty the inode itself */
-	if (flags & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) {
-		if (sb->s_op && sb->s_op->dirty_inode)
-			sb->s_op->dirty_inode(inode);
-	}
-
-	/* avoid the locking if we can */
-	if ((inode->i_state & flags) == flags)
-		return;
-
-	spin_lock(&inode_lock);
-	if ((inode->i_state & flags) != flags) {
-		inode->i_state |= flags;
-		/* Only add valid (ie hashed) inodes to the dirty list */
-		if (!(inode->i_state & I_LOCK) && !list_empty(&inode->i_hash)) {
-			list_del(&inode->i_list);
-			list_add(&inode->i_list, &sb->s_dirty);
-		}
-	}
-	spin_unlock(&inode_lock);
-}
-
-static void __wait_on_inode(struct inode * inode)
+void __wait_on_inode(struct inode * inode)
 {
 	DECLARE_WAITQUEUE(wait, current);
 
@@ -224,20 +174,10 @@
 	current->state = TASK_RUNNING;
 }
 
-static inline void wait_on_inode(struct inode *inode)
-{
-	if (inode->i_state & I_LOCK)
-		__wait_on_inode(inode);
-}
-
-
-static inline void write_inode(struct inode *inode, int sync)
-{
-	if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->write_inode && !is_bad_inode(inode))
-		inode->i_sb->s_op->write_inode(inode, sync);
-}
-
-static inline void __iget(struct inode * inode)
+/*
+ * inode_lock must be held
+ */
+void __iget(struct inode * inode)
 {
 	if (atomic_read(&inode->i_count)) {
 		atomic_inc(&inode->i_count);
@@ -251,287 +191,6 @@
 	inodes_stat.nr_unused--;
 }
 
-static inline void __sync_one(struct inode *inode, int sync)
-{
-	unsigned dirty;
-
-	list_del(&inode->i_list);
-	list_add(&inode->i_list, &inode->i_sb->s_locked_inodes);
-
-	if (inode->i_state & I_LOCK)
-		BUG();
-
-	/* Set I_LOCK, reset I_DIRTY */
-	dirty = inode->i_state & I_DIRTY;
-	inode->i_state |= I_LOCK;
-	inode->i_state &= ~I_DIRTY;
-	spin_unlock(&inode_lock);
-
-	filemap_fdatasync(inode->i_mapping);
-
-	/* Don't write the inode if only I_DIRTY_PAGES was set */
-	if (dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC))
-		write_inode(inode, sync);
-
-	filemap_fdatawait(inode->i_mapping);
-
-	spin_lock(&inode_lock);
-	inode->i_state &= ~I_LOCK;
-	if (!(inode->i_state & I_FREEING)) {
-		struct list_head *to;
-		if (inode->i_state & I_DIRTY)
-			to = &inode->i_sb->s_dirty;
-		else if (atomic_read(&inode->i_count))
-			to = &inode_in_use;
-		else
-			to = &inode_unused;
-		list_del(&inode->i_list);
-		list_add(&inode->i_list, to);
-	}
-	wake_up(&inode->i_wait);
-}
-
-static inline void sync_one(struct inode *inode, int sync)
-{
-	while (inode->i_state & I_LOCK) {
-		__iget(inode);
-		spin_unlock(&inode_lock);
-		__wait_on_inode(inode);
-		iput(inode);
-		spin_lock(&inode_lock);
-	}
-
-	__sync_one(inode, sync);
-}
-
-static inline void sync_list(struct list_head *head)
-{
-	struct list_head * tmp;
-
-	while ((tmp = head->prev) != head) 
-		__sync_one(list_entry(tmp, struct inode, i_list), 0);
-}
-
-static inline void wait_on_locked(struct list_head *head)
-{
-	struct list_head * tmp;
-	while ((tmp = head->prev) != head) {
-		struct inode *inode = list_entry(tmp, struct inode, i_list);
-		__iget(inode);
-		spin_unlock(&inode_lock);
-		__wait_on_inode(inode);
-		iput(inode);
-		spin_lock(&inode_lock);
-	}
-}
-
-static inline int try_to_sync_unused_list(struct list_head *head, int nr_inodes)
-{
-	struct list_head *tmp = head;
-	struct inode *inode;
-
-	while (nr_inodes && (tmp = tmp->prev) != head) {
-		inode = list_entry(tmp, struct inode, i_list);
-
-		if (!atomic_read(&inode->i_count)) {
-			__sync_one(inode, 0);
-			nr_inodes--;
-
-			/* 
-			 * __sync_one moved the inode to another list,
-			 * so we have to start looking from the list head.
-			 */
-			tmp = head;
-		}
-	}
-
-	return nr_inodes;
-}
-
-void sync_inodes_sb(struct super_block *sb)
-{
-	spin_lock(&inode_lock);
-	while (!list_empty(&sb->s_dirty)||!list_empty(&sb->s_locked_inodes)) {
-		sync_list(&sb->s_dirty);
-		wait_on_locked(&sb->s_locked_inodes);
-	}
-	spin_unlock(&inode_lock);
-}
-
-/*
- * Note:
- * We don't need to grab a reference to superblock here. If it has non-empty
- * ->s_dirty it's hadn't been killed yet and kill_super() won't proceed
- * past sync_inodes_sb() until both ->s_dirty and ->s_locked_inodes are
- * empty. Since __sync_one() regains inode_lock before it finally moves
- * inode from superblock lists we are OK.
- */
-
-void sync_unlocked_inodes(void)
-{
-	struct super_block * sb;
-	spin_lock(&inode_lock);
-	spin_lock(&sb_lock);
-	sb = sb_entry(super_blocks.next);
-	for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.next)) {
-		if (!list_empty(&sb->s_dirty)) {
-			spin_unlock(&sb_lock);
-			sync_list(&sb->s_dirty);
-			spin_lock(&sb_lock);
-		}
-	}
-	spin_unlock(&sb_lock);
-	spin_unlock(&inode_lock);
-}
-
-/*
- * Find a superblock with inodes that need to be synced
- */
-
-static struct super_block *get_super_to_sync(void)
-{
-	struct list_head *p;
-restart:
-	spin_lock(&inode_lock);
-	spin_lock(&sb_lock);
-	list_for_each(p, &super_blocks) {
-		struct super_block *s = list_entry(p,struct super_block,s_list);
-		if (list_empty(&s->s_dirty) && list_empty(&s->s_locked_inodes))
-			continue;
-		s->s_count++;
-		spin_unlock(&sb_lock);
-		spin_unlock(&inode_lock);
-		down_read(&s->s_umount);
-		if (!s->s_root) {
-			drop_super(s);
-			goto restart;
-		}
-		return s;
-	}
-	spin_unlock(&sb_lock);
-	spin_unlock(&inode_lock);
-	return NULL;
-}
-
-/**
- *	sync_inodes
- *	@dev: device to sync the inodes from.
- *
- *	sync_inodes goes through the super block's dirty list, 
- *	writes them out, and puts them back on the normal list.
- */
-
-void sync_inodes(void)
-{
-	struct super_block * s;
-	/*
-	 * Search the super_blocks array for the device(s) to sync.
-	 */
-	while ((s = get_super_to_sync()) != NULL) {
-		sync_inodes_sb(s);
-		drop_super(s);
-	}
-}
-
-static void try_to_sync_unused_inodes(unsigned long pexclusive)
-{
-	struct super_block * sb;
-	int nr_inodes = inodes_stat.nr_unused;
-
-	spin_lock(&inode_lock);
-	spin_lock(&sb_lock);
-	sb = sb_entry(super_blocks.next);
-	for (; nr_inodes && sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.next)) {
-		if (list_empty(&sb->s_dirty))
-			continue;
-		spin_unlock(&sb_lock);
-		nr_inodes = try_to_sync_unused_list(&sb->s_dirty, nr_inodes);
-		spin_lock(&sb_lock);
-	}
-	spin_unlock(&sb_lock);
-	spin_unlock(&inode_lock);
-	clear_bit(0, (unsigned long *)pexclusive);
-}
-
-/**
- *	write_inode_now	-	write an inode to disk
- *	@inode: inode to write to disk
- *	@sync: whether the write should be synchronous or not
- *
- *	This function commits an inode to disk immediately if it is
- *	dirty. This is primarily needed by knfsd.
- */
- 
-void write_inode_now(struct inode *inode, int sync)
-{
-	struct super_block * sb = inode->i_sb;
-
-	if (sb) {
-		spin_lock(&inode_lock);
-		sync_one(inode, sync);
-		spin_unlock(&inode_lock);
-		if (sync)
-			wait_on_inode(inode);
-	}
-	else
-		printk(KERN_ERR "write_inode_now: no super block\n");
-}
-
-/**
- * generic_osync_inode - flush all dirty data for a given inode to disk
- * @inode: inode to write
- * @datasync: if set, don't bother flushing timestamps
- *
- * This can be called by file_write functions for files which have the
- * O_SYNC flag set, to flush dirty writes to disk.  
- */
-
-int generic_osync_inode(struct inode *inode, int what)
-{
-	int err = 0, err2 = 0, need_write_inode_now = 0;
-	
-	/* 
-	 * WARNING
-	 *
-	 * Currently, the filesystem write path does not pass the
-	 * filp down to the low-level write functions.  Therefore it
-	 * is impossible for (say) __block_commit_write to know if
-	 * the operation is O_SYNC or not.
-	 *
-	 * Ideally, O_SYNC writes would have the filesystem call
-	 * ll_rw_block as it went to kick-start the writes, and we
-	 * could call osync_inode_buffers() here to wait only for
-	 * those IOs which have already been submitted to the device
-	 * driver layer.  As it stands, if we did this we'd not write
-	 * anything to disk since our writes have not been queued by
-	 * this point: they are still on the dirty LRU.
-	 * 
-	 * So, currently we will call fsync_inode_buffers() instead,
-	 * to flush _all_ dirty buffers for this inode to disk on 
-	 * every O_SYNC write, not just the synchronous I/Os.  --sct
-	 */
-
-	if (what & OSYNC_METADATA)
-		err = fsync_inode_buffers(inode);
-	if (what & OSYNC_DATA)
-		err2 = fsync_inode_data_buffers(inode);
-	if (!err)
-		err = err2;
-
-	spin_lock(&inode_lock);
-	if ((inode->i_state & I_DIRTY) &&
-	    ((what & OSYNC_INODE) || (inode->i_state & I_DIRTY_DATASYNC)))
-		need_write_inode_now = 1;
-	spin_unlock(&inode_lock);
-
-	if (need_write_inode_now)
-		write_inode_now(inode, 1);
-	else
-		wait_on_inode(inode);
-
-	return err;
-}
-
 /**
  * clear_inode - clear an inode
  * @inode: inode to clear
@@ -749,7 +408,7 @@
 		static unsigned long exclusive;
 
 		if (!test_and_set_bit(0, &exclusive)) {
-			if (pdflush_operation(try_to_sync_unused_inodes,
+			if (pdflush_operation(try_to_writeback_unused_inodes,
 						(unsigned long)&exclusive))
 				clear_bit(0, &exclusive);
 		}
diff -Nru a/fs/isofs/compress.c b/fs/isofs/compress.c
--- a/fs/isofs/compress.c	Tue Apr 30 17:10:23 2002
+++ b/fs/isofs/compress.c	Tue Apr 30 17:10:23 2002
@@ -164,7 +164,7 @@
 				flush_dcache_page(page);
 				SetPageUptodate(page);
 				kunmap(page);
-				UnlockPage(page);
+				unlock_page(page);
 				if ( fpage == xpage )
 					err = 0; /* The critical page */
 				else
@@ -282,7 +282,7 @@
 					flush_dcache_page(page);
 					SetPageUptodate(page);
 					kunmap(page);
-					UnlockPage(page);
+					unlock_page(page);
 					if ( fpage == xpage )
 						err = 0; /* The critical page */
 					else
@@ -313,7 +313,7 @@
 			if ( fpage == xpage )
 				SetPageError(page);
 			kunmap(page);
-			UnlockPage(page);
+			unlock_page(page);
 			if ( fpage != xpage )
 				page_cache_release(page);
 		}
diff -Nru a/fs/isofs/dir.c b/fs/isofs/dir.c
--- a/fs/isofs/dir.c	Tue Apr 30 17:10:25 2002
+++ b/fs/isofs/dir.c	Tue Apr 30 17:10:25 2002
@@ -21,6 +21,7 @@
 #include <linux/time.h>
 #include <linux/locks.h>
 #include <linux/config.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 
@@ -253,6 +254,8 @@
 	struct iso_directory_record * tmpde;
 	struct inode *inode = filp->f_dentry->d_inode;
 
+	lock_kernel();
+
 	tmpname = (char *) __get_free_page(GFP_KERNEL);
 	if (!tmpname)
 		return -ENOMEM;
@@ -261,5 +264,6 @@
 	result = do_isofs_readdir(inode, filp, dirent, filldir, tmpname, tmpde);
 
 	free_page((unsigned long) tmpname);
+	unlock_kernel();
 	return result;
 }
diff -Nru a/fs/isofs/rock.c b/fs/isofs/rock.c
--- a/fs/isofs/rock.c	Tue Apr 30 17:10:23 2002
+++ b/fs/isofs/rock.c	Tue Apr 30 17:10:23 2002
@@ -566,7 +566,7 @@
 	unlock_kernel();
 	SetPageUptodate(page);
 	kunmap(page);
-	UnlockPage(page);
+	unlock_page(page);
 	return 0;
 
 	/* error exit from macro */
@@ -584,7 +584,7 @@
 	unlock_kernel();
 	SetPageError(page);
 	kunmap(page);
-	UnlockPage(page);
+	unlock_page(page);
 	return -EIO;
 }
 
diff -Nru a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c
--- a/fs/jbd/checkpoint.c	Tue Apr 30 17:10:25 2002
+++ b/fs/jbd/checkpoint.c	Tue Apr 30 17:10:25 2002
@@ -62,8 +62,6 @@
 		__journal_remove_checkpoint(jh);
 		__journal_remove_journal_head(bh);
 		BUFFER_TRACE(bh, "release");
-		/* BUF_LOCKED -> BUF_CLEAN (fwiw) */
-		refile_buffer(bh);
 		__brelse(bh);
 		ret = 1;
 	}
@@ -149,8 +147,7 @@
 		/*
 		 * We used to test for (jh->b_list != BUF_CLEAN) here.
 		 * But unmap_underlying_metadata() can place buffer onto
-		 * BUF_CLEAN. Since refile_buffer() no longer takes buffers
-		 * off checkpoint lists, we cope with it here
+		 * BUF_CLEAN.
 		 */
 		/*
 		 * AKPM: I think the buffer_jdirty test is redundant - it
@@ -161,7 +158,6 @@
 			BUFFER_TRACE(bh, "remove from checkpoint");
 			__journal_remove_checkpoint(jh);
 			__journal_remove_journal_head(bh);
-			refile_buffer(bh);
 			__brelse(bh);
 			ret = 1;
 		}
diff -Nru a/fs/jbd/commit.c b/fs/jbd/commit.c
--- a/fs/jbd/commit.c	Tue Apr 30 17:10:25 2002
+++ b/fs/jbd/commit.c	Tue Apr 30 17:10:25 2002
@@ -29,7 +29,10 @@
 static void journal_end_buffer_io_sync(struct buffer_head *bh, int uptodate)
 {
 	BUFFER_TRACE(bh, "");
-	mark_buffer_uptodate(bh, uptodate);
+	if (uptodate)
+		set_buffer_uptodate(bh);
+	else
+		clear_buffer_uptodate(bh);
 	unlock_buffer(bh);
 }
 
@@ -210,7 +213,6 @@
 				__journal_unfile_buffer(jh);
 				jh->b_transaction = NULL;
 				__journal_remove_journal_head(bh);
-				refile_buffer(bh);
 				__brelse(bh);
 			}
 		}
@@ -291,10 +293,6 @@
 			jh->b_transaction = NULL;
 			__journal_remove_journal_head(bh);
 			BUFFER_TRACE(bh, "finished async writeout: refile");
-			/* It can sometimes be on BUF_LOCKED due to migration
-			 * from syncdata to asyncdata */
-			if (bh->b_list != BUF_CLEAN)
-				refile_buffer(bh);
 			__brelse(bh);
 		}
 	}
@@ -452,8 +450,9 @@
 			unlock_journal(journal);
 			for (i=0; i<bufs; i++) {
 				struct buffer_head *bh = wbuf[i];
-				set_bit(BH_Lock, &bh->b_state);
-				clear_bit(BH_Dirty, &bh->b_state);
+				set_buffer_locked(bh);
+				clear_buffer_dirty(bh);
+				set_buffer_uptodate(bh);
 				bh->b_end_io = journal_end_buffer_io_sync;
 				submit_bh(WRITE, bh);
 			}
@@ -514,7 +513,7 @@
 		journal_unlock_journal_head(jh);
 		__brelse(bh);
 		J_ASSERT_BH(bh, atomic_read(&bh->b_count) == 0);
-		put_unused_buffer_head(bh);
+		free_buffer_head(bh);
 
 		/* We also have to unlock and free the corresponding
                    shadowed buffer */
@@ -531,7 +530,7 @@
 		journal_file_buffer(jh, commit_transaction, BJ_Forget);
 		/* Wake up any transactions which were waiting for this
 		   IO to complete */
-		wake_up(&bh->b_wait);
+		wake_up_buffer(bh);
 		JBUFFER_TRACE(jh, "brelse shadowed buffer");
 		__brelse(bh);
 	}
@@ -592,6 +591,7 @@
 	JBUFFER_TRACE(descriptor, "write commit block");
 	{
 		struct buffer_head *bh = jh2bh(descriptor);
+		set_buffer_uptodate(bh);
 		ll_rw_block(WRITE, 1, &bh);
 		wait_on_buffer(bh);
 		__brelse(bh);		/* One for getblk() */
diff -Nru a/fs/jbd/journal.c b/fs/jbd/journal.c
--- a/fs/jbd/journal.c	Tue Apr 30 17:10:24 2002
+++ b/fs/jbd/journal.c	Tue Apr 30 17:10:24 2002
@@ -328,7 +328,6 @@
 			__journal_unfile_buffer(jh);
 			jh->b_transaction = NULL;
 			__journal_remove_journal_head(bh);
-			refile_buffer(bh);
 			__brelse(bh);
 			goto restart;
 		}
@@ -455,17 +454,15 @@
 	 * Right, time to make up the new buffer_head.
 	 */
 	do {
-		new_bh = get_unused_buffer_head(0);
+		new_bh = alloc_buffer_head(0);
 		if (!new_bh) {
 			printk (KERN_NOTICE __FUNCTION__
-				": ENOMEM at get_unused_buffer_head, "
+				": ENOMEM at alloc_buffer_head, "
 				"trying again.\n");
 			yield();
 		}
 	} while (!new_bh);
 	/* keep subsequent assertions sane */
-	new_bh->b_prev_free = 0;
-	new_bh->b_next_free = 0;
 	new_bh->b_state = 0;
 	init_buffer(new_bh, NULL, NULL);
 	atomic_set(&new_bh->b_count, 1);
@@ -477,7 +474,8 @@
 	new_bh->b_size = jh2bh(jh_in)->b_size;
 	new_bh->b_bdev = transaction->t_journal->j_dev;
 	new_bh->b_blocknr = blocknr;
-	new_bh->b_state |= (1 << BH_Mapped) | (1 << BH_Dirty);
+	set_buffer_mapped(new_bh);
+	set_buffer_dirty(new_bh);
 
 	*jh_out = new_jh;
 
@@ -889,7 +887,7 @@
 		BUFFER_TRACE(bh, "marking dirty");
 		mark_buffer_dirty(bh);
 		BUFFER_TRACE(bh, "marking uptodate");
-		mark_buffer_uptodate(bh, 1);
+		set_buffer_uptodate(bh);
 		unlock_buffer(bh);
 		__brelse(bh);
 	}
diff -Nru a/fs/jbd/recovery.c b/fs/jbd/recovery.c
--- a/fs/jbd/recovery.c	Tue Apr 30 17:10:25 2002
+++ b/fs/jbd/recovery.c	Tue Apr 30 17:10:25 2002
@@ -260,7 +260,7 @@
 	journal->j_transaction_sequence = ++info.end_transaction;
 		
 	journal_clear_revoke(journal);
-	fsync_no_super(journal->j_fs_dev);
+	sync_blockdev(journal->j_fs_dev);
 	return err;
 }
 
@@ -484,7 +484,7 @@
 					BUFFER_TRACE(nbh, "marking dirty");
 					mark_buffer_dirty(nbh);
 					BUFFER_TRACE(nbh, "marking uptodate");
-					mark_buffer_uptodate(nbh, 1);
+					set_buffer_uptodate(nbh);
 					++info->nr_replays;
 					/* ll_rw_block(WRITE, 1, &nbh); */
 					unlock_buffer(nbh);
diff -Nru a/fs/jbd/revoke.c b/fs/jbd/revoke.c
--- a/fs/jbd/revoke.c	Tue Apr 30 17:10:23 2002
+++ b/fs/jbd/revoke.c	Tue Apr 30 17:10:23 2002
@@ -406,11 +406,12 @@
 	 * buffer_head?  If so, we'd better make sure we clear the
 	 * revoked status on any hashed alias too, otherwise the revoke
 	 * state machine will get very upset later on. */
-	if (need_cancel && !bh->b_pprev) {
+	if (need_cancel) {
 		struct buffer_head *bh2;
 		bh2 = __get_hash_table(bh->b_bdev, bh->b_blocknr, bh->b_size);
 		if (bh2) {
-			clear_bit(BH_Revoked, &bh2->b_state);
+			if (bh2 != bh)
+				clear_bit(BH_Revoked, &bh2->b_state);
 			__brelse(bh2);
 		}
 	}
@@ -540,6 +541,7 @@
 	{
 		struct buffer_head *bh = jh2bh(descriptor);
 		BUFFER_TRACE(bh, "write");
+		set_buffer_uptodate(bh);
 		ll_rw_block (WRITE, 1, &bh);
 	}
 }
diff -Nru a/fs/jbd/transaction.c b/fs/jbd/transaction.c
--- a/fs/jbd/transaction.c	Tue Apr 30 17:10:25 2002
+++ b/fs/jbd/transaction.c	Tue Apr 30 17:10:25 2002
@@ -592,9 +592,6 @@
 			JBUFFER_TRACE(jh, "file as BJ_Reserved");
 			__journal_file_buffer(jh, transaction, BJ_Reserved);
 
-			/* And pull it off BUF_DIRTY, onto BUF_CLEAN */
-			refile_buffer(jh2bh(jh));
-
 			/*
 			 * The buffer is now hidden from bdflush.   It is
 			 * metadata against the current transaction.
@@ -657,7 +654,7 @@
 			spin_unlock(&journal_datalist_lock);
 			unlock_journal(journal);
 			/* commit wakes up all shadow buffers after IO */
-			sleep_on(&jh2bh(jh)->b_wait);
+			sleep_on_buffer(jh2bh(jh));
 			lock_journal(journal);
 			goto repeat;
 		}
@@ -812,8 +809,6 @@
 		jh->b_transaction = transaction;
 		JBUFFER_TRACE(jh, "file as BJ_Reserved");
 		__journal_file_buffer(jh, transaction, BJ_Reserved);
-		JBUFFER_TRACE(jh, "refile");
-		refile_buffer(jh2bh(jh));
 	} else if (jh->b_transaction == journal->j_committing_transaction) {
 		JBUFFER_TRACE(jh, "set next transaction");
 		jh->b_next_transaction = transaction;
@@ -1099,7 +1094,6 @@
 	
 	spin_lock(&journal_datalist_lock);
 	set_bit(BH_JBDDirty, &bh->b_state);
-	set_buffer_flushtime(bh);
 
 	J_ASSERT_JH(jh, jh->b_transaction != NULL);
 	
@@ -1208,7 +1202,7 @@
 		/* If we are forgetting a buffer which is already part
 		 * of this transaction, then we can just drop it from
 		 * the transaction immediately. */
-		clear_bit(BH_Dirty, &bh->b_state);
+		clear_buffer_dirty(bh);
 		clear_bit(BH_JBDDirty, &bh->b_state);
 
 		JBUFFER_TRACE(jh, "belongs to current transaction: unfile");
@@ -1553,9 +1547,8 @@
 	
 	__blist_del_buffer(list, jh);
 	jh->b_jlist = BJ_None;
-	if (test_and_clear_bit(BH_JBDDirty, &jh2bh(jh)->b_state)) {
-		set_bit(BH_Dirty, &jh2bh(jh)->b_state);
-	}
+	if (test_and_clear_bit(BH_JBDDirty, &jh2bh(jh)->b_state))
+		set_buffer_dirty(jh2bh(jh));
 }
 
 void journal_unfile_buffer(struct journal_head *jh)
@@ -1691,7 +1684,7 @@
 out:
 	ret = 0;
 	if (call_ttfb)
-		ret = try_to_free_buffers(page, gfp_mask);
+		ret = try_to_free_buffers(page);
 	return ret;
 }
 
@@ -1862,12 +1855,11 @@
 
 zap_buffer:	
 	if (buffer_dirty(bh))
-		mark_buffer_clean(bh);
+		clear_buffer_dirty(bh);
 	J_ASSERT_BH(bh, !buffer_jdirty(bh));
-	clear_bit(BH_Uptodate, &bh->b_state);
-	clear_bit(BH_Mapped, &bh->b_state);
-	clear_bit(BH_Req, &bh->b_state);
-	clear_bit(BH_New, &bh->b_state);
+	clear_buffer_mapped(bh);
+	clear_buffer_req(bh);
+	clear_buffer_new(bh);
 	bh->b_bdev = NULL;
 	return may_free;
 }
@@ -1913,7 +1905,7 @@
 	unlock_journal(journal);
 
 	if (!offset) {
-		if (!may_free || !try_to_free_buffers(page, 0))
+		if (!may_free || !try_to_free_buffers(page))
 			return 0;
 		J_ASSERT(!page_has_buffers(page));
 	}
@@ -1982,7 +1974,7 @@
 
 	if (jlist == BJ_Metadata || jlist == BJ_Reserved || 
 	    jlist == BJ_Shadow || jlist == BJ_Forget) {
-		if (atomic_set_buffer_clean(jh2bh(jh))) {
+		if (test_clear_buffer_dirty(jh2bh(jh))) {
 			set_bit(BH_JBDDirty, &jh2bh(jh)->b_state);
 		}
 	}
@@ -2021,9 +2013,6 @@
 	if (jh->b_transaction != NULL) {
 		__journal_file_buffer(jh, jh->b_transaction, BJ_Metadata);
 		J_ASSERT_JH(jh, jh->b_transaction->t_state == T_RUNNING);
-	} else {
-		/* Onto BUF_DIRTY for writeback */
-		refile_buffer(jh2bh(jh));
 	}
 }
 
diff -Nru a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c
--- a/fs/jffs/inode-v23.c	Tue Apr 30 17:10:23 2002
+++ b/fs/jffs/inode-v23.c	Tue Apr 30 17:10:23 2002
@@ -48,6 +48,7 @@
 #include <linux/stat.h>
 #include <linux/blkdev.h>
 #include <linux/quotaops.h>
+#include <linux/smp_lock.h>
 #include <asm/semaphore.h>
 #include <asm/byteorder.h>
 #include <asm/uaccess.h>
@@ -568,6 +569,7 @@
 	struct jffs_control *c = (struct jffs_control *)inode->i_sb->u.generic_sbp;
 	int j;
 	int ddino;
+	lock_kernel();
 	D3(printk (KERN_NOTICE "readdir(): down biglock\n"));
 	down(&c->fmc->biglock);
 
@@ -577,6 +579,7 @@
 		if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino, DT_DIR) < 0) {
 			D3(printk (KERN_NOTICE "readdir(): up biglock\n"));
 			up(&c->fmc->biglock);
+			unlock_kernel();
 			return 0;
 		}
 		filp->f_pos = 1;
@@ -593,6 +596,7 @@
 		if (filldir(dirent, "..", 2, filp->f_pos, ddino, DT_DIR) < 0) {
 			D3(printk (KERN_NOTICE "readdir(): up biglock\n"));
 			up(&c->fmc->biglock);
+			unlock_kernel();
 			return 0;
 		}
 		filp->f_pos++;
@@ -611,6 +615,7 @@
 			    filp->f_pos , f->ino, DT_UNKNOWN) < 0) {
 		        D3(printk (KERN_NOTICE "readdir(): up biglock\n"));
 			up(&c->fmc->biglock);
+			unlock_kernel();
 			return 0;
 		}
 		filp->f_pos++;
@@ -620,6 +625,7 @@
 	}
 	D3(printk (KERN_NOTICE "readdir(): up biglock\n"));
 	up(&c->fmc->biglock);
+	unlock_kernel();
 	return filp->f_pos;
 } /* jffs_readdir()  */
 
@@ -739,7 +745,7 @@
 		  (f->name ? f->name : ""), (long)page->index));
 
 	get_page(page);
-	/* Don't LockPage(page), should be locked already */
+	/* Don't SetPageLocked(page), should be locked already */
 	buf = page_address(page);
 	ClearPageUptodate(page);
 	ClearPageError(page);
@@ -789,7 +795,7 @@
 static int jffs_readpage(struct file *file, struct page *page)
 {
 	int ret = jffs_do_readpage_nolock(file, page);
-	UnlockPage(page);
+	unlock_page(page);
 	return ret;
 }
 
@@ -1519,7 +1525,7 @@
 	/* FIXME: we should detect some error conditions here */
 
 	/* Bugger that. We should make sure the page is uptodate */
-	if (!Page_Uptodate(page) && (from || to < PAGE_CACHE_SIZE))
+	if (!PageUptodate(page) && (from || to < PAGE_CACHE_SIZE))
 		return jffs_do_readpage_nolock(filp, page);
 
 	return 0;
diff -Nru a/fs/jffs2/dir.c b/fs/jffs2/dir.c
--- a/fs/jffs2/dir.c	Tue Apr 30 17:10:25 2002
+++ b/fs/jffs2/dir.c	Tue Apr 30 17:10:25 2002
@@ -45,6 +45,7 @@
 #include <linux/jffs2_fs_i.h>
 #include <linux/jffs2_fs_sb.h>
 #include <linux/time.h>
+#include <linux/smp_lock.h>
 #include "nodelist.h"
 
 static int jffs2_readdir (struct file *, void *, filldir_t);
@@ -143,6 +144,8 @@
 
 	D1(printk(KERN_DEBUG "jffs2_readdir() for dir_i #%lu\n", filp->f_dentry->d_inode->i_ino));
 
+	lock_kernel();
+
 	f = JFFS2_INODE_INFO(inode);
 	c = JFFS2_SB_INFO(inode->i_sb);
 
@@ -186,6 +189,7 @@
 	up(&f->sem);
  out:
 	filp->f_pos = offset;
+	unlock_kernel();
 	return 0;
 }
 
diff -Nru a/fs/jffs2/file.c b/fs/jffs2/file.c
--- a/fs/jffs2/file.c	Tue Apr 30 17:10:25 2002
+++ b/fs/jffs2/file.c	Tue Apr 30 17:10:25 2002
@@ -281,7 +281,7 @@
 int jffs2_do_readpage_unlock(struct inode *inode, struct page *pg)
 {
 	int ret = jffs2_do_readpage_nolock(inode, pg);
-	UnlockPage(pg);
+	unlock_page(pg);
 	return ret;
 }
 
@@ -371,7 +371,7 @@
 	
 
 	/* Read in the page if it wasn't already present */
-	if (!Page_Uptodate(pg) && (start || end < PAGE_SIZE))
+	if (!PageUptodate(pg) && (start || end < PAGE_SIZE))
 		ret = jffs2_do_readpage_nolock(inode, pg);
 	D1(printk(KERN_DEBUG "end prepare_write()\n"));
 	up(&f->sem);
diff -Nru a/fs/jffs2/gc.c b/fs/jffs2/gc.c
--- a/fs/jffs2/gc.c	Tue Apr 30 17:10:25 2002
+++ b/fs/jffs2/gc.c	Tue Apr 30 17:10:25 2002
@@ -760,7 +760,7 @@
 
 	kunmap(pg);
 	/* XXX: Does the page get freed automatically? */
-	/* AAA: Judging by the unmount getting stuck in __wait_on_page, nope. */
+	/* AAA: Judging by the unmount getting stuck in __wait_on_page_locked, nope. */
 	page_cache_release(pg);
 	return ret;
 }
diff -Nru a/fs/jfs/file.c b/fs/jfs/file.c
--- a/fs/jfs/file.c	Tue Apr 30 17:10:25 2002
+++ b/fs/jfs/file.c	Tue Apr 30 17:10:25 2002
@@ -33,8 +33,6 @@
 	struct inode *inode = dentry->d_inode;
 	int rc = 0;
 
-	rc = fsync_inode_data_buffers(inode);
-
 	if (!(inode->i_state & I_DIRTY))
 		return rc;
 	if (datasync || !(inode->i_state & I_DIRTY_DATASYNC))
diff -Nru a/fs/jfs/inode.c b/fs/jfs/inode.c
--- a/fs/jfs/inode.c	Tue Apr 30 17:10:23 2002
+++ b/fs/jfs/inode.c	Tue Apr 30 17:10:23 2002
@@ -229,7 +229,7 @@
 			rc = extRecord(ip, &xad);
 			if (rc)
 				goto unlock;
-			bh_result->b_state |= (1UL << BH_New);
+			set_buffer_new(bh_result);
 		}
 
 		map_bh(bh_result, ip->i_sb, xaddr);
@@ -249,7 +249,7 @@
 	if (rc)
 		goto unlock;
 
-	bh_result->b_state |= (1UL << BH_New);
+	set_buffer_new(bh_result);
 	map_bh(bh_result, ip->i_sb, addressXAD(&xad));
 
 #else				/* _JFS_4K */
diff -Nru a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c
--- a/fs/jfs/jfs_dmap.c	Tue Apr 30 17:10:25 2002
+++ b/fs/jfs/jfs_dmap.c	Tue Apr 30 17:10:25 2002
@@ -325,7 +325,9 @@
 	/*
 	 * write out dirty pages of bmap
 	 */
-	fsync_inode_data_buffers(ipbmap);
+	filemap_fdatawait(ipbmap->i_mapping);
+	filemap_fdatawrite(ipbmap->i_mapping);
+	filemap_fdatawait(ipbmap->i_mapping);
 
 	ipbmap->i_state |= I_DIRTY;
 	diWriteSpecial(ipbmap);
diff -Nru a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c
--- a/fs/jfs/jfs_dtree.c	Tue Apr 30 17:10:24 2002
+++ b/fs/jfs/jfs_dtree.c	Tue Apr 30 17:10:24 2002
@@ -102,6 +102,7 @@
 
 #include <linux/fs.h>
 #include <linux/locks.h>
+#include <linux/smp_lock.h>
 #include "jfs_incore.h"
 #include "jfs_superblock.h"
 #include "jfs_filsys.h"
@@ -2868,6 +2869,8 @@
 	if (filp->f_pos == DIREND)
 		return 0;
 
+	lock_kernel();
+
 	if (DO_INDEX(ip)) {
 		/*
 		 * persistent index is stored in directory entries.
@@ -2885,12 +2888,14 @@
 
 			if (dtEmpty(ip)) {
 				filp->f_pos = DIREND;
+				unlock_kernel();
 				return 0;
 			}
 		      repeat:
 			rc = get_index(ip, dir_index, &dirtab_slot);
 			if (rc) {
 				filp->f_pos = DIREND;
+				unlock_kernel();
 				return rc;
 			}
 			if (dirtab_slot.flag == DIR_INDEX_FREE) {
@@ -2898,11 +2903,13 @@
 					jERROR(1, ("jfs_readdir detected "
 						   "infinite loop!\n"));
 					filp->f_pos = DIREND;
+					unlock_kernel();
 					return 0;
 				}
 				dir_index = le32_to_cpu(dirtab_slot.addr2);
 				if (dir_index == -1) {
 					filp->f_pos = DIREND;
+					unlock_kernel();
 					return 0;
 				}
 				goto repeat;
@@ -2912,12 +2919,14 @@
 			DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
 			if (rc) {
 				filp->f_pos = DIREND;
+				unlock_kernel();
 				return 0;
 			}
 			if (p->header.flag & BT_INTERNAL) {
 				jERROR(1,("jfs_readdir: bad index table\n"));
 				DT_PUTPAGE(mp);
 				filp->f_pos = -1;
+				unlock_kernel();
 				return 0;
 			}
 		} else {
@@ -2927,27 +2936,34 @@
 				 */
 				filp->f_pos = 0;
 				if (filldir(dirent, ".", 1, 0, ip->i_ino,
-					    DT_DIR))
+					    DT_DIR)) {
+					unlock_kernel();	
 					return 0;
+				}
 			}
 			/*
 			 * parent ".."
 			 */
 			filp->f_pos = 1;
 			if (filldir
-			    (dirent, "..", 2, 1, PARENT(ip), DT_DIR))
+			    (dirent, "..", 2, 1, PARENT(ip), DT_DIR)) {
+				unlock_kernel();
 				return 0;
+			}
 
 			/*
 			 * Find first entry of left-most leaf
 			 */
 			if (dtEmpty(ip)) {
 				filp->f_pos = DIREND;
+				unlock_kernel();
 				return 0;
 			}
 
-			if ((rc = dtReadFirst(ip, &btstack)))
+			if ((rc = dtReadFirst(ip, &btstack))) {
+				unlock_kernel();
 				return -rc;
+			}
 
 			DT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
 		}
@@ -2966,8 +2982,10 @@
 			/* build "." entry */
 
 			if (filldir(dirent, ".", 1, filp->f_pos, ip->i_ino,
-				    DT_DIR))
+				    DT_DIR)) {
+				unlock_kernel();
 				return 0;
+			}
 			dtoffset->index = 1;
 		}
 
@@ -2976,8 +2994,10 @@
 				/* build ".." entry */
 
 				if (filldir(dirent, "..", 2, filp->f_pos,
-					    PARENT(ip), DT_DIR))
+					    PARENT(ip), DT_DIR)) {
+					unlock_kernel();
 					return 0;
+				}
 			} else {
 				jERROR(1,
 				       ("jfs_readdir called with invalid offset!\n"));
@@ -2988,6 +3008,7 @@
 
 		if (dtEmpty(ip)) {
 			filp->f_pos = DIREND;
+			unlock_kernel();
 			return 0;
 		}
 
@@ -2996,6 +3017,7 @@
 			       ("jfs_readdir: unexpected rc = %d from dtReadNext\n",
 				rc));
 			filp->f_pos = DIREND;
+			unlock_kernel();
 			return 0;
 		}
 		/* get start leaf page and index */
@@ -3004,6 +3026,7 @@
 		/* offset beyond directory eof ? */
 		if (bn < 0) {
 			filp->f_pos = DIREND;
+			unlock_kernel();
 			return 0;
 		}
 	}
@@ -3013,6 +3036,7 @@
 		DT_PUTPAGE(mp);
 		jERROR(1, ("jfs_readdir: kmalloc failed!\n"));
 		filp->f_pos = DIREND;
+		unlock_kernel();
 		return 0;
 	}
 	while (1) {
@@ -3087,6 +3111,7 @@
 		DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
 		if (rc) {
 			kfree(d_name);
+			unlock_kernel();
 			return -rc;
 		}
 
@@ -3102,7 +3127,7 @@
       out:
 	kfree(d_name);
 	DT_PUTPAGE(mp);
-
+	unlock_kernel();
 	return rc;
 }
 
diff -Nru a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c
--- a/fs/jfs/jfs_imap.c	Tue Apr 30 17:10:24 2002
+++ b/fs/jfs/jfs_imap.c	Tue Apr 30 17:10:24 2002
@@ -282,7 +282,9 @@
 	/*
 	 * write out dirty pages of imap
 	 */
-	fsync_inode_data_buffers(ipimap);
+	filemap_fdatawait(ipimap->i_mapping);
+	filemap_fdatawrite(ipimap->i_mapping);
+	filemap_fdatawait(ipimap->i_mapping);
 
 	diWriteSpecial(ipimap);
 
@@ -607,7 +609,9 @@
 		jERROR(1, ("diFreeSpecial called with NULL ip!\n"));
 		return;
 	}
-	fsync_inode_data_buffers(ip);
+	filemap_fdatawait(ip->i_mapping);
+	filemap_fdatawrite(ip->i_mapping);
+	filemap_fdatawait(ip->i_mapping);
 	truncate_inode_pages(ip->i_mapping, 0);
 	iput(ip);
 }
diff -Nru a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
--- a/fs/jfs/jfs_logmgr.c	Tue Apr 30 17:10:25 2002
+++ b/fs/jfs/jfs_logmgr.c	Tue Apr 30 17:10:25 2002
@@ -966,9 +966,15 @@
 		 * We need to make sure all of the "written" metapages
 		 * actually make it to disk
 		 */
-		fsync_inode_data_buffers(sbi->ipbmap);
-		fsync_inode_data_buffers(sbi->ipimap);
-		fsync_inode_data_buffers(sbi->direct_inode);
+		filemap_fdatawait(sbi->ipbmap->i_mapping);
+		filemap_fdatawait(sbi->ipimap->i_mapping);
+		filemap_fdatawait(sbi->direct_inode->i_mapping);
+		filemap_fdatawrite(sbi->ipbmap->i_mapping);
+		filemap_fdatawrite(sbi->ipimap->i_mapping);
+		filemap_fdatawrite(sbi->direct_inode->i_mapping);
+		filemap_fdatawait(sbi->ipbmap->i_mapping);
+		filemap_fdatawait(sbi->ipimap->i_mapping);
+		filemap_fdatawait(sbi->direct_inode->i_mapping);
 
 		lrd.logtid = 0;
 		lrd.backchain = 0;
@@ -1072,6 +1078,7 @@
 	 */
 
 	log->sb = sb;		/* This should be a list */
+	log->bdev = sb->s_bdev;
 	log->flag = JFS_INLINELOG;
 	log->base = addressPXD(&JFS_SBI(sb)->logpxd);
 	log->size = lengthPXD(&JFS_SBI(sb)->logpxd) >>
@@ -1426,7 +1433,7 @@
 	 * We need to make sure all of the "written" metapages
 	 * actually make it to disk
 	 */
-	fsync_no_super(log->sb->s_bdev);
+	sync_blockdev(log->sb->s_bdev);
 
 	/*
 	 * write the last SYNCPT record with syncpoint = 0
diff -Nru a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c
--- a/fs/jfs/jfs_metapage.c	Tue Apr 30 17:10:25 2002
+++ b/fs/jfs/jfs_metapage.c	Tue Apr 30 17:10:25 2002
@@ -267,7 +267,7 @@
 			    struct buffer_head *bh_result, int create)
 {
 	if (create)
-		bh_result->b_state |= (1UL << BH_New);
+		set_buffer_new(bh_result);
 
 	map_bh(bh_result, ip->i_sb, lblock);
 
@@ -349,7 +349,7 @@
 		page_index = lblock >> l2BlocksPerPage;
 		page_offset = (lblock - (page_index << l2BlocksPerPage)) <<
 		    l2bsize;
-		if ((page_offset + size) > PAGE_SIZE) {
+		if ((page_offset + size) > PAGE_CACHE_SIZE) {
 			spin_unlock(&meta_lock);
 			jERROR(1, ("MetaData crosses page boundary!!\n"));
 			return NULL;
@@ -394,8 +394,10 @@
 				__free_metapage(mp);
 				spin_unlock(&meta_lock);
 				return NULL;
-			} else
+			} else {
 				INCREMENT(mpStat.pagealloc);
+				unlock_page(mp->page);
+			}
 		} else {
 			jFYI(1,
 			     ("__get_metapage: Calling read_cache_page\n"));
@@ -412,7 +414,6 @@
 				return NULL;
 			} else
 				INCREMENT(mpStat.pagealloc);
-			lock_page(mp->page);
 		}
 		mp->data = (void *) (kmap(mp->page) + page_offset);
 	}
@@ -459,6 +460,7 @@
 	page_offset =
 	    (mp->index - (page_index << l2BlocksPerPage)) << l2bsize;
 
+	lock_page(mp->page);
 	rc = mp->mapping->a_ops->prepare_write(NULL, mp->page, page_offset,
 					       page_offset +
 					       mp->logical_size);
@@ -466,6 +468,7 @@
 		jERROR(1, ("prepare_write return %d!\n", rc));
 		ClearPageUptodate(mp->page);
 		kunmap(mp->page);
+		unlock_page(mp->page);
 		clear_bit(META_dirty, &mp->flag);
 		return;
 	}
@@ -476,6 +479,7 @@
 		jERROR(1, ("commit_write returned %d\n", rc));
 	}
 
+	unlock_page(mp->page);
 	clear_bit(META_dirty, &mp->flag);
 
 	jFYI(1, ("__write_metapage done\n"));
@@ -489,12 +493,10 @@
 	lock_page(page);
 
 	/* we're done with this page - no need to check for errors */
-	if (page_has_buffers(page)) {
-		writeout_one_page(page);
-		waitfor_one_page(page);
-	}
-
-	UnlockPage(page);
+	if (page_has_buffers(page))
+		write_one_page(page, 1);
+	else
+		unlock_page(page);
 	page_cache_release(page);
 }
 
@@ -527,7 +529,6 @@
 			mp->data = 0;
 			if (test_bit(META_dirty, &mp->flag))
 				__write_metapage(mp);
-			UnlockPage(mp->page);
 			if (test_bit(META_sync, &mp->flag)) {
 				sync_metapage(mp);
 				clear_bit(META_sync, &mp->flag);
@@ -536,7 +537,7 @@
 			if (test_bit(META_discard, &mp->flag)) {
 				lock_page(mp->page);
 				block_flushpage(mp->page, 0);
-				UnlockPage(mp->page);
+				unlock_page(mp->page);
 			}
 
 			page_cache_release(mp->page);
@@ -587,13 +588,15 @@
 			/*
 			 * If in the metapage cache, we've got the page locked
 			 */
+			lock_page(mp->page);
 			block_flushpage(mp->page, 0);
+			unlock_page(mp->page);
 		} else {
 			spin_unlock(&meta_lock);
 			page = find_lock_page(mapping, lblock>>l2BlocksPerPage);
 			if (page) {
 				block_flushpage(page, 0);
-				UnlockPage(page);
+				unlock_page(page);
 			}
 		}
 	}
@@ -610,7 +613,6 @@
 		clear_bit(META_dirty, &mp->flag);
 		set_bit(META_discard, &mp->flag);
 		kunmap(mp->page);
-		UnlockPage(mp->page);
 		page_cache_release(mp->page);
 		INCREMENT(mpStat.pagefree);
 		mp->data = 0;
diff -Nru a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
--- a/fs/jfs/jfs_txnmgr.c	Tue Apr 30 17:10:23 2002
+++ b/fs/jfs/jfs_txnmgr.c	Tue Apr 30 17:10:23 2002
@@ -1155,7 +1155,7 @@
 		jfs_ip = JFS_IP(ip);
 
 		/*
-		 * BUGBUG - Should we call filemap_fdatasync here instead
+		 * BUGBUG - Should we call filemap_fdatawrite here instead
 		 * of fsync_inode_data?
 		 * If we do, we have a deadlock condition since we may end
 		 * up recursively calling jfs_get_block with the IWRITELOCK
@@ -1163,8 +1163,11 @@
 		 * committing transactions and use i_sem instead.
 		 */
 		if ((!S_ISDIR(ip->i_mode))
-		    && (tblk->flag & COMMIT_DELETE) == 0)
-			fsync_inode_data_buffers(ip);
+		    && (tblk->flag & COMMIT_DELETE) == 0) {
+			filemap_fdatawait(ip->i_mapping);
+			filemap_fdatawrite(ip->i_mapping);
+			filemap_fdatawait(ip->i_mapping);
+		}
 
 		/*
 		 * Mark inode as not dirty.  It will still be on the dirty
diff -Nru a/fs/jfs/namei.c b/fs/jfs/namei.c
--- a/fs/jfs/namei.c	Tue Apr 30 17:10:25 2002
+++ b/fs/jfs/namei.c	Tue Apr 30 17:10:25 2002
@@ -969,7 +969,7 @@
 				memcpy(mp->data, name, copy_size);
 				flush_metapage(mp);
 #if 0
-				mark_buffer_uptodate(bp, 1);
+				set_buffer_uptodate(bp);
 				mark_buffer_dirty(bp, 1);
 				if (IS_SYNC(dip)) {
 					ll_rw_block(WRITE, 1, &bp);
diff -Nru a/fs/jfs/super.c b/fs/jfs/super.c
--- a/fs/jfs/super.c	Tue Apr 30 17:10:25 2002
+++ b/fs/jfs/super.c	Tue Apr 30 17:10:25 2002
@@ -151,7 +151,9 @@
 	 * We need to clean out the direct_inode pages since this inode
 	 * is not in the inode hash.
 	 */
-	fsync_inode_data_buffers(sbi->direct_inode);
+	filemap_fdatawait(sbi->direct_inode->i_mapping);
+	filemap_fdatawrite(sbi->direct_inode->i_mapping);
+	filemap_fdatawait(sbi->direct_inode->i_mapping);
 	truncate_inode_pages(sbi->direct_mapping, 0);
 	iput(sbi->direct_inode);
 	sbi->direct_inode = NULL;
@@ -337,7 +339,9 @@
 		jERROR(1, ("jfs_umount failed with return code %d\n", rc));
 	}
 out_mount_failed:
-	fsync_inode_data_buffers(sbi->direct_inode);
+	filemap_fdatawait(sbi->direct_inode->i_mapping);
+	filemap_fdatawrite(sbi->direct_inode->i_mapping);
+	filemap_fdatawait(sbi->direct_inode->i_mapping);
 	truncate_inode_pages(sbi->direct_mapping, 0);
 	make_bad_inode(sbi->direct_inode);
 	iput(sbi->direct_inode);
diff -Nru a/fs/libfs.c b/fs/libfs.c
--- a/fs/libfs.c	Tue Apr 30 17:10:23 2002
+++ b/fs/libfs.c	Tue Apr 30 17:10:23 2002
@@ -4,6 +4,7 @@
  */
 
 #include <linux/pagemap.h>
+#include <linux/smp_lock.h>
 
 int simple_statfs(struct super_block *sb, struct statfs *buf)
 {
@@ -40,6 +41,8 @@
 	int i;
 	struct dentry *dentry = filp->f_dentry;
 
+	lock_kernel();
+
 	i = filp->f_pos;
 	switch (i) {
 		case 0:
@@ -64,6 +67,7 @@
 			for (;;) {
 				if (list == &dentry->d_subdirs) {
 					spin_unlock(&dcache_lock);
+					unlock_kernel();
 					return 0;
 				}
 				if (!j)
@@ -94,6 +98,7 @@
 			}
 		}
 	}
+	unlock_kernel();
 	return 0;
 }
 
diff -Nru a/fs/minix/dir.c b/fs/minix/dir.c
--- a/fs/minix/dir.c	Tue Apr 30 17:10:25 2002
+++ b/fs/minix/dir.c	Tue Apr 30 17:10:25 2002
@@ -7,6 +7,7 @@
  */
 
 #include "minix.h"
+#include <linux/smp_lock.h>
 
 typedef struct minix_dir_entry minix_dirent;
 
@@ -24,6 +25,20 @@
 	page_cache_release(page);
 }
 
+/*
+ * Return the offset into page `page_nr' of the last valid
+ * byte in that page, plus one.
+ */
+static unsigned
+minix_last_byte(struct inode *inode, unsigned long page_nr)
+{
+	unsigned last_byte = PAGE_CACHE_SIZE;
+
+	if (page_nr == (inode->i_size >> PAGE_CACHE_SHIFT))
+		last_byte = inode->i_size & (PAGE_CACHE_SIZE - 1);
+	return last_byte;
+}
+
 static inline unsigned long dir_pages(struct inode *inode)
 {
 	return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT;
@@ -34,13 +49,10 @@
 	struct inode *dir = (struct inode *)page->mapping->host;
 	int err = 0;
 	page->mapping->a_ops->commit_write(NULL, page, from, to);
-	if (IS_SYNC(dir)) {
-		int err2;
-		err = writeout_one_page(page);
-		err2 = waitfor_one_page(page);
-		if (err == 0)
-			err = err2;
-	}
+	if (IS_SYNC(dir))
+		err = write_one_page(page, 1);
+	else
+		unlock_page(page);
 	return err;
 }
 
@@ -50,9 +62,9 @@
 	struct page *page = read_cache_page(mapping, n,
 				(filler_t*)mapping->a_ops->readpage, NULL);
 	if (!IS_ERR(page)) {
-		wait_on_page(page);
+		wait_on_page_locked(page);
 		kmap(page);
-		if (!Page_Uptodate(page))
+		if (!PageUptodate(page))
 			goto fail;
 	}
 	return page;
@@ -78,6 +90,8 @@
 	struct minix_sb_info *sbi = minix_sb(sb);
 	unsigned chunk_size = sbi->s_dirsize;
 
+	lock_kernel();
+
 	pos = (pos + chunk_size-1) & ~(chunk_size-1);
 	if (pos >= inode->i_size)
 		goto done;
@@ -90,7 +104,7 @@
 			continue;
 		kaddr = (char *)page_address(page);
 		p = kaddr+offset;
-		limit = kaddr + PAGE_CACHE_SIZE - chunk_size;
+		limit = kaddr + minix_last_byte(inode, n) - chunk_size;
 		for ( ; p <= limit ; p = minix_next_entry(p, sbi)) {
 			minix_dirent *de = (minix_dirent *)p;
 			if (de->inode) {
@@ -113,6 +127,7 @@
 done:
 	filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset;
 	UPDATE_ATIME(inode);
+	unlock_kernel();
 	return 0;
 }
 
@@ -154,7 +169,7 @@
 
 		kaddr = (char*)page_address(page);
 		de = (struct minix_dir_entry *) kaddr;
-		kaddr += PAGE_CACHE_SIZE - sbi->s_dirsize;
+		kaddr += minix_last_byte(dir, n) - sbi->s_dirsize;
 		for ( ; (char *) de <= kaddr ; de = minix_next_entry(de,sbi)) {
 			if (!de->inode)
 				continue;
@@ -185,23 +200,37 @@
 	unsigned from, to;
 	int err;
 
-	/* We take care of directory expansion in the same loop */
+	/*
+	 * We take care of directory expansion in the same loop
+	 * This code plays outside i_size, so it locks the page
+	 * to protect that region.
+	 */
 	for (n = 0; n <= npages; n++) {
+		char *dir_end;
+
 		page = dir_get_page(dir, n);
 		err = PTR_ERR(page);
 		if (IS_ERR(page))
 			goto out;
+		lock_page(page);
 		kaddr = (char*)page_address(page);
+		dir_end = kaddr + minix_last_byte(dir, n);
 		de = (minix_dirent *)kaddr;
 		kaddr += PAGE_CACHE_SIZE - sbi->s_dirsize;
 		while ((char *)de <= kaddr) {
+			if ((char *)de == dir_end) {
+				/* We hit i_size */
+				de->inode = 0;
+				goto got_it;
+			}
 			if (!de->inode)
 				goto got_it;
 			err = -EEXIST;
 			if (namecompare(namelen,sbi->s_namelen,name,de->name))
-				goto out_page;
+				goto out_unlock;
 			de = minix_next_entry(de, sbi);
 		}
+		unlock_page(page);
 		dir_put_page(page);
 	}
 	BUG();
@@ -210,7 +239,6 @@
 got_it:
 	from = (char*)de - (char*)page_address(page);
 	to = from + sbi->s_dirsize;
-	lock_page(page);
 	err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
 	if (err)
 		goto out_unlock;
@@ -220,12 +248,13 @@
 	err = dir_commit_chunk(page, from, to);
 	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
 	mark_inode_dirty(dir);
-out_unlock:
-	UnlockPage(page);
-out_page:
+out_put:
 	dir_put_page(page);
 out:
 	return err;
+out_unlock:
+	unlock_page(page);
+	goto out_put;
 }
 
 int minix_delete_entry(struct minix_dir_entry *de, struct page *page)
@@ -242,8 +271,9 @@
 	if (err == 0) {
 		de->inode = 0;
 		err = dir_commit_chunk(page, from, to);
+	} else {
+		unlock_page(page);
 	}
-	UnlockPage(page);
 	dir_put_page(page);
 	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
 	mark_inode_dirty(inode);
@@ -262,8 +292,10 @@
 	if (!page)
 		return -ENOMEM;
 	err = mapping->a_ops->prepare_write(NULL, page, 0, 2 * sbi->s_dirsize);
-	if (err)
+	if (err) {
+		unlock_page(page);
 		goto fail;
+	}
 
 	base = (char*)page_address(page);
 	memset(base, 0, PAGE_CACHE_SIZE);
@@ -277,7 +309,6 @@
 
 	err = dir_commit_chunk(page, 0, 2 * sbi->s_dirsize);
 fail:
-	UnlockPage(page);
 	page_cache_release(page);
 	return err;
 }
@@ -301,7 +332,7 @@
 
 		kaddr = (char *)page_address(page);
 		de = (minix_dirent *)kaddr;
-		kaddr += PAGE_CACHE_SIZE - sbi->s_dirsize;
+		kaddr += minix_last_byte(inode, i) - sbi->s_dirsize;
 
 		while ((char *)de <= kaddr) {
 			if (de->inode != 0) {
@@ -342,8 +373,9 @@
 	if (err == 0) {
 		de->inode = inode->i_ino;
 		err = dir_commit_chunk(page, from, to);
+	} else {
+		unlock_page(page);
 	}
-	UnlockPage(page);
 	dir_put_page(page);
 	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
 	mark_inode_dirty(dir);
diff -Nru a/fs/minix/file.c b/fs/minix/file.c
--- a/fs/minix/file.c	Tue Apr 30 17:10:25 2002
+++ b/fs/minix/file.c	Tue Apr 30 17:10:25 2002
@@ -32,7 +32,6 @@
 	int err;
 
 	err = fsync_inode_buffers(inode);
-	err |= fsync_inode_data_buffers(inode);
 	if (!(inode->i_state & I_DIRTY))
 		return err;
 	if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
diff -Nru a/fs/minix/itree_common.c b/fs/minix/itree_common.c
--- a/fs/minix/itree_common.c	Tue Apr 30 17:10:25 2002
+++ b/fs/minix/itree_common.c	Tue Apr 30 17:10:25 2002
@@ -89,7 +89,7 @@
 		branch[n].bh = bh;
 		branch[n].p = (block_t*) bh->b_data + offsets[n];
 		*branch[n].p = branch[n].key;
-		mark_buffer_uptodate(bh, 1);
+		set_buffer_uptodate(bh);
 		unlock_buffer(bh);
 		mark_buffer_dirty_inode(bh, inode);
 		parent = nr;
@@ -194,7 +194,7 @@
 	if (splice_branch(inode, chain, partial, left) < 0)
 		goto changed;
 
-	bh->b_state |= (1UL << BH_New);
+	set_buffer_new(bh);
 	goto got_it;
 
 changed:
diff -Nru a/fs/namei.c b/fs/namei.c
--- a/fs/namei.c	Tue Apr 30 17:10:25 2002
+++ b/fs/namei.c	Tue Apr 30 17:10:25 2002
@@ -279,36 +279,24 @@
 }
 
 /*for fastwalking*/
-static inline void undo_locked(struct nameidata *nd)
+static inline void unlock_nd(struct nameidata *nd)
 {
-	if(nd->flags & LOOKUP_LOCKED){
-		dget_locked(nd->dentry);
-		mntget(nd->mnt);
-		spin_unlock(&dcache_lock);
-		nd->flags &= ~LOOKUP_LOCKED;
-	}
+	struct vfsmount *mnt = nd->old_mnt;
+	struct dentry *dentry = nd->old_dentry;
+	mntget(nd->mnt);
+	dget_locked(nd->dentry);
+	nd->old_mnt = NULL;
+	nd->old_dentry = NULL;
+	spin_unlock(&dcache_lock);
+	dput(dentry);
+	mntput(mnt);
 }
 
-/*
- * For fast path lookup while holding the dcache_lock. 
- * SMP-safe
- */
-static struct dentry * cached_lookup_nd(struct nameidata * nd, struct qstr * name, int flags)
+static inline void lock_nd(struct nameidata *nd)
 {
-	struct dentry * dentry = NULL;
-	if(!(nd->flags & LOOKUP_LOCKED))
-		return cached_lookup(nd->dentry, name, flags);
-	
-	dentry = __d_lookup(nd->dentry, name);
-	
-	if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
-		undo_locked(nd);
-		if (!dentry->d_op->d_revalidate(dentry, flags) && !d_invalidate(dentry)) {
-			dput(dentry);
-			dentry = NULL;
-		}
-	}
-	return dentry;
+	spin_lock(&dcache_lock);
+	nd->old_mnt = nd->mnt;
+	nd->old_dentry = nd->dentry;
 }
 
 /*
@@ -326,7 +314,7 @@
 	umode_t	mode = inode->i_mode;
 
 	if ((inode->i_op && inode->i_op->permission))
-		return -EACCES;
+		return -EAGAIN;
 
 	if (current->fsuid == inode->i_uid)
 		mode >>= 6;
@@ -418,10 +406,10 @@
 	return -ELOOP;
 }
 
-static inline int __follow_up(struct vfsmount **mnt, struct dentry **base)
+int follow_up(struct vfsmount **mnt, struct dentry **dentry)
 {
 	struct vfsmount *parent;
-	struct dentry *dentry;
+	struct dentry *mountpoint;
 	spin_lock(&dcache_lock);
 	parent=(*mnt)->mnt_parent;
 	if (parent == *mnt) {
@@ -429,18 +417,27 @@
 		return 0;
 	}
 	mntget(parent);
-	dentry=dget((*mnt)->mnt_mountpoint);
+	mountpoint=dget((*mnt)->mnt_mountpoint);
 	spin_unlock(&dcache_lock);
-	dput(*base);
-	*base = dentry;
+	dput(*dentry);
+	*dentry = mountpoint;
 	mntput(*mnt);
 	*mnt = parent;
 	return 1;
 }
 
-int follow_up(struct vfsmount **mnt, struct dentry **dentry)
+static int follow_mount(struct vfsmount **mnt, struct dentry **dentry)
 {
-	return __follow_up(mnt, dentry);
+	int res = 0;
+	while (d_mountpoint(*dentry)) {
+		struct vfsmount *mounted = lookup_mnt(*mnt, *dentry);
+		if (!mounted)
+			break;
+		*mnt = mounted;
+		*dentry = mounted->mnt_root;
+		res = 1;
+	}
+	return res;
 }
 
 static inline int __follow_down(struct vfsmount **mnt, struct dentry **dentry)
@@ -466,41 +463,83 @@
 	return __follow_down(mnt,dentry);
 }
  
-static inline void follow_dotdot(struct nameidata *nd)
+static inline void follow_dotdot(struct vfsmount **mnt, struct dentry **dentry)
 {
 	while(1) {
 		struct vfsmount *parent;
-		struct dentry *dentry;
-		read_lock(&current->fs->lock);
-		if (nd->dentry == current->fs->root &&
-		    nd->mnt == current->fs->rootmnt)  {
-			read_unlock(&current->fs->lock);
+		if (*dentry == current->fs->root &&
+		    *mnt == current->fs->rootmnt)
 			break;
-		}
-		read_unlock(&current->fs->lock);
-		spin_lock(&dcache_lock);
-		if (nd->dentry != nd->mnt->mnt_root) {
-			dentry = dget(nd->dentry->d_parent);
-			spin_unlock(&dcache_lock);
-			dput(nd->dentry);
-			nd->dentry = dentry;
+		if (*dentry != (*mnt)->mnt_root) {
+			*dentry = (*dentry)->d_parent;
 			break;
 		}
-		parent=nd->mnt->mnt_parent;
-		if (parent == nd->mnt) {
-			spin_unlock(&dcache_lock);
+		parent=(*mnt)->mnt_parent;
+		if (parent == *mnt)
 			break;
-		}
-		mntget(parent);
-		dentry=dget(nd->mnt->mnt_mountpoint);
-		spin_unlock(&dcache_lock);
-		dput(nd->dentry);
-		nd->dentry = dentry;
-		mntput(nd->mnt);
-		nd->mnt = parent;
+		*dentry=(*mnt)->mnt_mountpoint;
+		*mnt = parent;
 	}
-	while (d_mountpoint(nd->dentry) && __follow_down(&nd->mnt, &nd->dentry))
-		;
+	follow_mount(mnt, dentry);
+}
+
+struct path {
+	struct vfsmount *mnt;
+	struct dentry *dentry;
+};
+
+/*
+ *  It's more convoluted than I'd like it to be, but... it's still fairly
+ *  small and for now I'd prefer to have fast path as straight as possible.
+ *  It _is_ time-critical.
+ */
+static int do_lookup(struct nameidata *nd, struct qstr *name,
+		     struct path *path, struct path *cached_path,
+		     int flags)
+{
+	struct vfsmount *mnt = nd->mnt;
+	struct dentry *dentry = __d_lookup(nd->dentry, name);
+
+	if (!dentry)
+		goto dcache_miss;
+	if (dentry->d_op && dentry->d_op->d_revalidate)
+		goto need_revalidate;
+done:
+	path->mnt = mnt;
+	path->dentry = dentry;
+	return 0;
+
+dcache_miss:
+	unlock_nd(nd);
+
+need_lookup:
+	dentry = real_lookup(nd->dentry, name, LOOKUP_CONTINUE);
+	if (IS_ERR(dentry))
+		goto fail;
+	mntget(mnt);
+relock:
+	dput(cached_path->dentry);
+	mntput(cached_path->mnt);
+	cached_path->mnt = mnt;
+	cached_path->dentry = dentry;
+	lock_nd(nd);
+	goto done;
+
+need_revalidate:
+	mntget(mnt);
+	dget_locked(dentry);
+	unlock_nd(nd);
+	if (dentry->d_op->d_revalidate(dentry, flags))
+		goto relock;
+	if (d_invalidate(dentry))
+		goto relock;
+	dput(dentry);
+	mntput(mnt);
+	goto need_lookup;
+
+fail:
+	lock_nd(nd);
+	return PTR_ERR(dentry);
 }
 
 /*
@@ -513,11 +552,11 @@
  */
 int link_path_walk(const char * name, struct nameidata *nd)
 {
-	struct dentry *dentry;
+	struct path next, pinned = {NULL, NULL};
 	struct inode *inode;
 	int err;
 	unsigned int lookup_flags = nd->flags;
-
+	
 	while (*name=='/')
 		name++;
 	if (!*name)
@@ -534,11 +573,11 @@
 		unsigned int c;
 
 		err = exec_permission_lite(inode);
-		if(err){
-			undo_locked(nd);
+		if (err == -EAGAIN) {
+			unlock_nd(nd);
 			err = permission(inode, MAY_EXEC);
+			lock_nd(nd);
 		}
-		dentry = ERR_PTR(err);
  		if (err)
 			break;
 
@@ -572,8 +611,7 @@
 			case 2:	
 				if (this.name[1] != '.')
 					break;
-				undo_locked(nd);
-				follow_dotdot(nd);
+				follow_dotdot(&nd->mnt, &nd->dentry);
 				inode = nd->dentry->d_inode;
 				/* fallthrough */
 			case 1:
@@ -589,35 +627,30 @@
 				break;
 		}
 		/* This does the actual lookups.. */
-		dentry = cached_lookup_nd(nd, &this, LOOKUP_CONTINUE);
-		if (!dentry) {
-			undo_locked(nd);
-			dentry = real_lookup(nd->dentry, &this, LOOKUP_CONTINUE);
-			err = PTR_ERR(dentry);
-			if (IS_ERR(dentry))
-				break;
-		}
+		err = do_lookup(nd, &this, &next, &pinned, LOOKUP_CONTINUE);
+		if (err)
+			break;
 		/* Check mountpoints.. */
-		if(d_mountpoint(dentry)){
-			undo_locked(nd);
-			while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry))
-				;
-		}
+		follow_mount(&next.mnt, &next.dentry);
 
 		err = -ENOENT;
-		inode = dentry->d_inode;
+		inode = next.dentry->d_inode;
 		if (!inode)
-			goto out_dput;
+			break;
 		err = -ENOTDIR; 
 		if (!inode->i_op)
-			goto out_dput;
+			break;
 
 		if (inode->i_op->follow_link) {
-			undo_locked(nd);
-			err = do_follow_link(dentry, nd);
-			dput(dentry);
+			mntget(next.mnt);
+			dget_locked(next.dentry);
+			unlock_nd(nd);
+			err = do_follow_link(next.dentry, nd);
+			dput(next.dentry);
+			mntput(next.mnt);
 			if (err)
 				goto return_err;
+			lock_nd(nd);
 			err = -ENOENT;
 			inode = nd->dentry->d_inode;
 			if (!inode)
@@ -626,9 +659,8 @@
 			if (!inode->i_op)
 				break;
 		} else {
-			if (!(nd->flags & LOOKUP_LOCKED))
-				dput(nd->dentry);
-			nd->dentry = dentry;
+			nd->mnt = next.mnt;
+			nd->dentry = next.dentry;
 		}
 		err = -ENOTDIR; 
 		if (!inode->i_op->lookup)
@@ -647,8 +679,7 @@
 			case 2:	
 				if (this.name[1] != '.')
 					break;
-				undo_locked(nd);
-				follow_dotdot(nd);
+				follow_dotdot(&nd->mnt, &nd->dentry);
 				inode = nd->dentry->d_inode;
 				/* fallthrough */
 			case 1:
@@ -659,27 +690,26 @@
 			if (err < 0)
 				break;
 		}
-		dentry = cached_lookup_nd(nd, &this, 0);
-		undo_locked(nd); 
-		if (!dentry) {
-			dentry = real_lookup(nd->dentry, &this, 0);
-			err = PTR_ERR(dentry);
-			if (IS_ERR(dentry))
-				break;
-		}
-		while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry))
-			;
-		inode = dentry->d_inode;
+		err = do_lookup(nd, &this, &next, &pinned, 0);
+		if (err)
+			break;
+		follow_mount(&next.mnt, &next.dentry);
+		inode = next.dentry->d_inode;
 		if ((lookup_flags & LOOKUP_FOLLOW)
 		    && inode && inode->i_op && inode->i_op->follow_link) {
-			err = do_follow_link(dentry, nd);
-			dput(dentry);
+			mntget(next.mnt);
+			dget_locked(next.dentry);
+			unlock_nd(nd);
+			err = do_follow_link(next.dentry, nd);
+			dput(next.dentry);
+			mntput(next.mnt);
 			if (err)
 				goto return_err;
 			inode = nd->dentry->d_inode;
+			lock_nd(nd);
 		} else {
-			dput(nd->dentry);
-			nd->dentry = dentry;
+			nd->mnt = next.mnt;
+			nd->dentry = next.dentry;
 		}
 		err = -ENOENT;
 		if (!inode)
@@ -700,22 +730,23 @@
 		else if (this.len == 2 && this.name[1] == '.')
 			nd->last_type = LAST_DOTDOT;
 return_base:
-		undo_locked(nd);
+		unlock_nd(nd);
+		dput(pinned.dentry);
+		mntput(pinned.mnt);
 		return 0;
-out_dput:
-		undo_locked(nd);
-		dput(dentry);
-		break;
 	}
-	undo_locked(nd);
+	unlock_nd(nd);
 	path_release(nd);
 return_err:
+	dput(pinned.dentry);
+	mntput(pinned.mnt);
 	return err;
 }
 
 int path_walk(const char * name, struct nameidata *nd)
 {
 	current->total_link_count = 0;
+	lock_nd(nd);
 	return link_path_walk(name, nd);
 }
 
@@ -803,6 +834,8 @@
 int path_init(const char *name, unsigned int flags, struct nameidata *nd)
 {
 	nd->last_type = LAST_ROOT; /* if there are only slashes... */
+	nd->old_mnt = NULL;
+	nd->old_dentry = NULL;
 	nd->flags = flags;
 	if (*name=='/')
 		return walk_init_root(name,nd);
@@ -817,7 +850,7 @@
 {
 	nd->last_type = LAST_ROOT; /* if there are only slashes... */
 	nd->flags = flags;
-	if (*name=='/'){
+	if (*name=='/') {
 		read_lock(&current->fs->lock);
 		if (current->fs->altroot && !(nd->flags & LOOKUP_NOALT)) {
 			nd->mnt = mntget(current->fs->altrootmnt);
@@ -827,20 +860,20 @@
 				return 0;
 			read_lock(&current->fs->lock);
 		}
-		spin_lock(&dcache_lock); /*to avoid cacheline bouncing with d_count*/
+		read_unlock(&current->fs->lock);
+		spin_lock(&dcache_lock);
 		nd->mnt = current->fs->rootmnt;
 		nd->dentry = current->fs->root;
-		read_unlock(&current->fs->lock);
 	}
 	else{
-		read_lock(&current->fs->lock);
 		spin_lock(&dcache_lock);
 		nd->mnt = current->fs->pwdmnt;
 		nd->dentry = current->fs->pwd;
-		read_unlock(&current->fs->lock);
 	}
-	nd->flags |= LOOKUP_LOCKED;
-	return (path_walk(name, nd));
+	nd->old_mnt = NULL;
+	nd->old_dentry = NULL;
+	current->total_link_count = 0;
+	return link_path_walk(name, nd);
 }
 
 /*
@@ -2029,6 +2062,7 @@
 			/* weird __emul_prefix() stuff did it */
 			goto out;
 	}
+	lock_nd(nd);
 	res = link_path_walk(link, nd);
 out:
 	if (current->link_count || res || nd->last_type!=LAST_NORM)
@@ -2063,8 +2097,8 @@
 				NULL);
 	if (IS_ERR(page))
 		goto sync_fail;
-	wait_on_page(page);
-	if (!Page_Uptodate(page))
+	wait_on_page_locked(page);
+	if (!PageUptodate(page))
 		goto async_fail;
 	*ppage = page;
 	return kmap(page);
diff -Nru a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
--- a/fs/ncpfs/dir.c	Tue Apr 30 17:10:23 2002
+++ b/fs/ncpfs/dir.c	Tue Apr 30 17:10:23 2002
@@ -400,6 +400,8 @@
 	int result, mtime_valid = 0;
 	time_t mtime = 0;
 
+	lock_kernel();
+
 	ctl.page  = NULL;
 	ctl.cache = NULL;
 
@@ -430,7 +432,7 @@
 	ctl.cache = cache = kmap(page);
 	ctl.head  = cache->head;
 
-	if (!Page_Uptodate(page) || !ctl.head.eof)
+	if (!PageUptodate(page) || !ctl.head.eof)
 		goto init_cache;
 
 	if (filp->f_pos == 2) {
@@ -456,7 +458,7 @@
 			if (!ctl.page)
 				goto invalid_cache;
 			ctl.cache = kmap(ctl.page);
-			if (!Page_Uptodate(ctl.page))
+			if (!PageUptodate(ctl.page))
 				goto invalid_cache;
 		}
 		while (ctl.idx < NCP_DIRCACHE_SIZE) {
@@ -481,7 +483,7 @@
 		if (ctl.page) {
 			kunmap(ctl.page);
 			SetPageUptodate(ctl.page);
-			UnlockPage(ctl.page);
+			unlock_page(ctl.page);
 			page_cache_release(ctl.page);
 			ctl.page = NULL;
 		}
@@ -491,7 +493,7 @@
 invalid_cache:
 	if (ctl.page) {
 		kunmap(ctl.page);
-		UnlockPage(ctl.page);
+		unlock_page(ctl.page);
 		page_cache_release(ctl.page);
 		ctl.page = NULL;
 	}
@@ -523,16 +525,17 @@
 		cache->head = ctl.head;
 		kunmap(page);
 		SetPageUptodate(page);
-		UnlockPage(page);
+		unlock_page(page);
 		page_cache_release(page);
 	}
 	if (ctl.page) {
 		kunmap(ctl.page);
 		SetPageUptodate(ctl.page);
-		UnlockPage(ctl.page);
+		unlock_page(ctl.page);
 		page_cache_release(ctl.page);
 	}
 out:
+	unlock_kernel();
 	return result;
 }
 
@@ -597,7 +600,7 @@
 		if (ctl.page) {
 			kunmap(ctl.page);
 			SetPageUptodate(ctl.page);
-			UnlockPage(ctl.page);
+			unlock_page(ctl.page);
 			page_cache_release(ctl.page);
 		}
 		ctl.cache = NULL;
diff -Nru a/fs/ncpfs/symlink.c b/fs/ncpfs/symlink.c
--- a/fs/ncpfs/symlink.c	Tue Apr 30 17:10:25 2002
+++ b/fs/ncpfs/symlink.c	Tue Apr 30 17:10:25 2002
@@ -81,7 +81,7 @@
 		goto fail;
 	SetPageUptodate(page);
 	kunmap(page);
-	UnlockPage(page);
+	unlock_page(page);
 	return 0;
 
 failEIO:
@@ -90,7 +90,7 @@
 fail:
 	SetPageError(page);
 	kunmap(page);
-	UnlockPage(page);
+	unlock_page(page);
 	return error;
 }
 
diff -Nru a/fs/nfs/dir.c b/fs/nfs/dir.c
--- a/fs/nfs/dir.c	Tue Apr 30 17:10:25 2002
+++ b/fs/nfs/dir.c	Tue Apr 30 17:10:25 2002
@@ -123,12 +123,12 @@
 	 */
 	if (page->index == 0)
 		invalidate_inode_pages(inode);
-	UnlockPage(page);
+	unlock_page(page);
 	return 0;
  error:
 	SetPageError(page);
 	kunmap(page);
-	UnlockPage(page);
+	unlock_page(page);
 	invalidate_inode_pages(inode);
 	desc->error = error;
 	return -EIO;
@@ -202,7 +202,7 @@
 		status = PTR_ERR(page);
 		goto out;
 	}
-	if (!Page_Uptodate(page))
+	if (!PageUptodate(page))
 		goto read_error;
 
 	/* NOTE: Someone else may have changed the READDIRPLUS flag */
@@ -355,9 +355,13 @@
 	struct nfs_entry my_entry;
 	long		res;
 
+	lock_kernel();
+
 	res = nfs_revalidate(dentry);
-	if (res < 0)
+	if (res < 0) {
+		unlock_kernel();
 		return res;
+	}
 
 	/*
 	 * filp->f_pos points to the file offset in the page cache.
@@ -394,6 +398,7 @@
 			break;
 		}
 	}
+	unlock_kernel();
 	if (desc->error < 0)
 		return desc->error;
 	if (res < 0)
diff -Nru a/fs/nfs/file.c b/fs/nfs/file.c
--- a/fs/nfs/file.c	Tue Apr 30 17:10:25 2002
+++ b/fs/nfs/file.c	Tue Apr 30 17:10:25 2002
@@ -169,7 +169,7 @@
 }
 
 /*
- * The following is used by wait_on_page(), generic_file_readahead()
+ * The following is used by wait_on_page_locked(), generic_file_readahead()
  * to initiate the completion of any page readahead operations.
  */
 static int nfs_sync_page(struct page *page)
@@ -279,14 +279,17 @@
 	 * Flush all pending writes before doing anything
 	 * with locks..
 	 */
-	status = filemap_fdatasync(inode->i_mapping);
+	status = filemap_fdatawait(inode->i_mapping);
+	status2 = filemap_fdatawrite(inode->i_mapping);
+	if (!status)
+		status = status2;
 	down(&inode->i_sem);
 	status2 = nfs_wb_all(inode);
-	if (status2 && !status)
+	if (!status)
 		status = status2;
 	up(&inode->i_sem);
 	status2 = filemap_fdatawait(inode->i_mapping);
-	if (status2 && !status)
+	if (!status)
 		status = status2;
 	if (status < 0)
 		return status;
@@ -305,7 +308,8 @@
 	 */
  out_ok:
 	if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
-		filemap_fdatasync(inode->i_mapping);
+		filemap_fdatawait(inode->i_mapping);
+		filemap_fdatawrite(inode->i_mapping);
 		down(&inode->i_sem);
 		nfs_wb_all(inode);      /* we may have slept */
 		up(&inode->i_sem);
diff -Nru a/fs/nfs/inode.c b/fs/nfs/inode.c
--- a/fs/nfs/inode.c	Tue Apr 30 17:10:25 2002
+++ b/fs/nfs/inode.c	Tue Apr 30 17:10:25 2002
@@ -749,7 +749,8 @@
 	if (!S_ISREG(inode->i_mode))
 		attr->ia_valid &= ~ATTR_SIZE;
 
-	filemap_fdatasync(inode->i_mapping);
+	filemap_fdatawait(inode->i_mapping);
+	filemap_fdatawrite(inode->i_mapping);
 	error = nfs_wb_all(inode);
 	filemap_fdatawait(inode->i_mapping);
 	if (error)
diff -Nru a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
--- a/fs/nfs/nfs3proc.c	Tue Apr 30 17:10:25 2002
+++ b/fs/nfs/nfs3proc.c	Tue Apr 30 17:10:25 2002
@@ -14,6 +14,7 @@
 #include <linux/nfs.h>
 #include <linux/nfs3.h>
 #include <linux/nfs_fs.h>
+#include <linux/smp_lock.h>
 
 #define NFSDBG_FACILITY		NFSDBG_PROC
 
@@ -560,6 +561,8 @@
 	u32			*verf = NFS_COOKIEVERF(dir);
 	int			status;
 
+	lock_kernel();
+
 	arg.buffer  = entry;
 	arg.bufsiz  = size;
 	arg.verf[0] = verf[0];
@@ -580,6 +583,7 @@
 	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
 	nfs_refresh_inode(dir, &dir_attr);
 	dprintk("NFS reply readdir: %d\n", status);
+	unlock_kernel();
 	return status;
 }
 
diff -Nru a/fs/nfs/proc.c b/fs/nfs/proc.c
--- a/fs/nfs/proc.c	Tue Apr 30 17:10:25 2002
+++ b/fs/nfs/proc.c	Tue Apr 30 17:10:25 2002
@@ -41,6 +41,7 @@
 #include <linux/nfs.h>
 #include <linux/nfs2.h>
 #include <linux/nfs_fs.h>
+#include <linux/smp_lock.h>
 
 #define NFSDBG_FACILITY		NFSDBG_PROC
 
@@ -440,6 +441,8 @@
 	};
 	int			status;
 
+	lock_kernel();
+
 	arg.fh = NFS_FH(dir);
 	arg.cookie = cookie;
 	arg.buffer = entry;
@@ -451,6 +454,7 @@
 	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
 
 	dprintk("NFS reply readdir: %d\n", status);
+	unlock_kernel();
 	return status;
 }
 
diff -Nru a/fs/nfs/read.c b/fs/nfs/read.c
--- a/fs/nfs/read.c	Tue Apr 30 17:10:23 2002
+++ b/fs/nfs/read.c	Tue Apr 30 17:10:23 2002
@@ -145,7 +145,7 @@
 
 io_error:
 	kunmap(page);
-	UnlockPage(page);
+	unlock_page(page);
 	return result;
 }
 
@@ -226,7 +226,7 @@
 		page = req->wb_page;
 		nfs_list_remove_request(req);
 		SetPageError(page);
-		UnlockPage(page);
+		unlock_page(page);
 		nfs_clear_request(req);
 		nfs_release_request(req);
 		nfs_unlock_request(req);
@@ -430,7 +430,7 @@
 			SetPageError(page);
 		flush_dcache_page(page);
 		kunmap(page);
-		UnlockPage(page);
+		unlock_page(page);
 
 		dprintk("NFS: read (%s/%Ld %d@%Ld)\n",
                         req->wb_inode->i_sb->s_id,
@@ -483,7 +483,7 @@
 	return error;
 
 out_error:
-	UnlockPage(page);
+	unlock_page(page);
 	goto out;
 }
 
diff -Nru a/fs/nfs/symlink.c b/fs/nfs/symlink.c
--- a/fs/nfs/symlink.c	Tue Apr 30 17:10:23 2002
+++ b/fs/nfs/symlink.c	Tue Apr 30 17:10:23 2002
@@ -44,13 +44,13 @@
 		goto error;
 	SetPageUptodate(page);
 	kunmap(page);
-	UnlockPage(page);
+	unlock_page(page);
 	return 0;
 
 error:
 	SetPageError(page);
 	kunmap(page);
-	UnlockPage(page);
+	unlock_page(page);
 	return -EIO;
 }
 
@@ -64,7 +64,7 @@
 				(filler_t *)nfs_symlink_filler, inode);
 	if (IS_ERR(page))
 		goto read_failed;
-	if (!Page_Uptodate(page))
+	if (!PageUptodate(page))
 		goto getlink_read_error;
 	*ppage = page;
 	p = kmap(page);
diff -Nru a/fs/nfs/write.c b/fs/nfs/write.c
--- a/fs/nfs/write.c	Tue Apr 30 17:10:25 2002
+++ b/fs/nfs/write.c	Tue Apr 30 17:10:25 2002
@@ -272,7 +272,7 @@
 	}
 	unlock_kernel();
 out:
-	UnlockPage(page);
+	unlock_page(page);
 	return err; 
 }
 
diff -Nru a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
--- a/fs/nfsd/vfs.c	Tue Apr 30 17:10:25 2002
+++ b/fs/nfsd/vfs.c	Tue Apr 30 17:10:25 2002
@@ -508,7 +508,8 @@
 	struct inode *inode = dp->d_inode;
 	int (*fsync) (struct file *, struct dentry *, int);
 
-	filemap_fdatasync(inode->i_mapping);
+	filemap_fdatawait(inode->i_mapping);
+	filemap_fdatawrite(inode->i_mapping);
 	if (fop && (fsync = fop->fsync))
 		fsync(filp, dp, 0);
 	filemap_fdatawait(inode->i_mapping);
diff -Nru a/fs/ntfs/aops.c b/fs/ntfs/aops.c
--- a/fs/ntfs/aops.c	Tue Apr 30 17:10:25 2002
+++ b/fs/ntfs/aops.c	Tue Apr 30 17:10:25 2002
@@ -48,7 +48,10 @@
 	struct buffer_head *tmp;
 	struct page *page;
 
-	mark_buffer_uptodate(bh, uptodate);
+	if (uptodate)
+		set_buffer_uptodate(bh);
+	else
+		clear_buffer_uptodate(bh);
 
 	page = bh->b_page;
 
@@ -73,7 +76,7 @@
 		SetPageError(page);
 
 	spin_lock_irqsave(&page_uptodate_lock, flags);
-	mark_buffer_async(bh, 0);
+	clear_buffer_async(bh);
 	unlock_buffer(bh);
 
 	tmp = bh->b_this_page;
@@ -89,7 +92,7 @@
 	spin_unlock_irqrestore(&page_uptodate_lock, flags);
 	if (!PageError(page))
 		SetPageUptodate(page);
-	UnlockPage(page);
+	unlock_page(page);
 	return;
 still_busy:
 	spin_unlock_irqrestore(&page_uptodate_lock, flags);
@@ -120,7 +123,7 @@
 	blocksize = 1 << blocksize_bits;
 
 	if (!page_has_buffers(page))
-		create_empty_buffers(page, blocksize);
+		create_empty_buffers(page, blocksize, 0);
 	bh = head = page_buffers(page);
 	if (!bh)
 		return -ENOMEM;
@@ -167,7 +170,7 @@
 				/* Setup buffer head to correct block. */
 				bh->b_blocknr = ((lcn << vol->cluster_size_bits)
 						+ vcn_ofs) >> blocksize_bits;
-				bh->b_state |= (1UL << BH_Mapped);
+				set_buffer_mapped(bh);
 				/* Only read initialized data blocks. */
 				if (iblock < zblock) {
 					arr[nr++] = bh;
@@ -200,12 +203,12 @@
 		 */
 handle_hole:
 		bh->b_blocknr = -1UL;
-		bh->b_state &= ~(1UL << BH_Mapped);
+		clear_buffer_mapped(bh);
 handle_zblock:
 		memset(kmap(page) + i * blocksize, 0, blocksize);
 		flush_dcache_page(page);
 		kunmap(page);
-		set_bit(BH_Uptodate, &bh->b_state);
+		set_buffer_uptodate(bh);
 	} while (i++, iblock++, (bh = bh->b_this_page) != head);
 
 	/* Check we have at least one buffer ready for i/o. */
@@ -215,7 +218,7 @@
 			struct buffer_head *tbh = arr[i];
 			lock_buffer(tbh);
 			tbh->b_end_io = end_buffer_read_file_async;
-			mark_buffer_async(tbh, 1);
+			set_buffer_async(tbh);
 		}
 		/* Finally, start i/o on the buffers. */
 		for (i = 0; i < nr; i++)
@@ -227,7 +230,7 @@
 		SetPageUptodate(page);
 	else /* Signal synchronous i/o error. */
 		nr = -EIO;
-	UnlockPage(page);
+	unlock_page(page);
 	return nr;
 }
 
@@ -329,7 +332,7 @@
 unm_unl_err_out:
 	unmap_mft_record(READ, ni);
 unl_err_out:
-	UnlockPage(page);
+	unlock_page(page);
 	return err;
 }
 
@@ -346,7 +349,10 @@
 	struct buffer_head *tmp;
 	struct page *page;
 
-	mark_buffer_uptodate(bh, uptodate);
+	if (uptodate)
+		set_buffer_uptodate(bh);
+	else
+		clear_buffer_uptodate(bh);
 
 	page = bh->b_page;
 
@@ -372,7 +378,7 @@
 		SetPageError(page);
 
 	spin_lock_irqsave(&page_uptodate_lock, flags);
-	mark_buffer_async(bh, 0);
+	clear_buffer_async(bh);
 	unlock_buffer(bh);
 
 	tmp = bh->b_this_page;
@@ -388,7 +394,7 @@
 	spin_unlock_irqrestore(&page_uptodate_lock, flags);
 	if (!PageError(page))
 		SetPageUptodate(page);
-	UnlockPage(page);
+	unlock_page(page);
 	return;
 still_busy:
 	spin_unlock_irqrestore(&page_uptodate_lock, flags);
@@ -417,7 +423,7 @@
 	blocksize_bits = vol->sb->s_blocksize_bits;
 
 	if (!page_has_buffers(page))
-		create_empty_buffers(page, blocksize);
+		create_empty_buffers(page, blocksize, 0);
 	bh = head = page_buffers(page);
 	if (!bh)
 		return -ENOMEM;
@@ -454,7 +460,7 @@
 				/* Setup buffer head to correct block. */
 				bh->b_blocknr = ((lcn << vol->cluster_size_bits)
 						+ vcn_ofs) >> blocksize_bits;
-				bh->b_state |= (1UL << BH_Mapped);
+				set_buffer_mapped(bh);
 				/* Only read initialized data blocks. */
 				if (iblock < zblock) {
 					arr[nr++] = bh;
@@ -480,12 +486,12 @@
 		 * the buffer uptodate.
 		 */
 		bh->b_blocknr = -1UL;
-		bh->b_state &= ~(1UL << BH_Mapped);
+		clear_buffer_mapped(bh);
 handle_zblock:
 		memset(kmap(page) + i * blocksize, 0, blocksize);
 		flush_dcache_page(page);
 		kunmap(page);
-		set_bit(BH_Uptodate, &bh->b_state);
+		set_buffer_uptodate(bh);
 	} while (i++, iblock++, (bh = bh->b_this_page) != head);
 
 	/* Check we have at least one buffer ready for i/o. */
@@ -495,7 +501,7 @@
 			struct buffer_head *tbh = arr[i];
 			lock_buffer(tbh);
 			tbh->b_end_io = end_buffer_read_mftbmp_async;
-			mark_buffer_async(tbh, 1);
+			set_buffer_async(tbh);
 		}
 		/* Finally, start i/o on the buffers. */
 		for (i = 0; i < nr; i++)
@@ -507,7 +513,7 @@
 		SetPageUptodate(page);
 	else /* Signal synchronous i/o error. */
 		nr = -EIO;
-	UnlockPage(page);
+	unlock_page(page);
 	return nr;
 }
 
@@ -539,7 +545,10 @@
 	struct page *page;
 	ntfs_inode *ni;
 
-	mark_buffer_uptodate(bh, uptodate);
+	if (uptodate)
+		set_buffer_uptodate(bh);
+	else
+		clear_buffer_uptodate(bh);
 
 	page = bh->b_page;
 
@@ -565,7 +574,7 @@
 		SetPageError(page);
 
 	spin_lock_irqsave(&page_uptodate_lock, flags);
-	mark_buffer_async(bh, 0);
+	clear_buffer_async(bh);
 	unlock_buffer(bh);
 
 	tmp = bh->b_this_page;
@@ -613,7 +622,7 @@
 			SetPageError(page);
 		}
 	}
-	UnlockPage(page);
+	unlock_page(page);
 	return;
 still_busy:
 	spin_unlock_irqrestore(&page_uptodate_lock, flags);
@@ -656,7 +665,7 @@
 	blocksize = 1 << blocksize_bits;
 
 	if (!page_has_buffers(page))
-		create_empty_buffers(page, blocksize);
+		create_empty_buffers(page, blocksize, 0);
 	bh = head = page_buffers(page);
 	if (!bh)
 		return -ENOMEM;
@@ -701,7 +710,7 @@
 				/* Setup buffer head to correct block. */
 				bh->b_blocknr = ((lcn << vol->cluster_size_bits)
 						+ vcn_ofs) >> blocksize_bits;
-				bh->b_state |= (1UL << BH_Mapped);
+				set_buffer_mapped(bh);
 				/* Only read initialized data blocks. */
 				if (iblock < zblock) {
 					arr[nr++] = bh;
@@ -734,12 +743,12 @@
 		 */
 handle_hole:
 		bh->b_blocknr = -1UL;
-		bh->b_state &= ~(1UL << BH_Mapped);
+		clear_buffer_mapped(bh);
 handle_zblock:
 		memset(kmap(page) + i * blocksize, 0, blocksize);
 		flush_dcache_page(page);
 		kunmap(page);
-		set_bit(BH_Uptodate, &bh->b_state);
+		set_buffer_uptodate(bh);
 	} while (i++, iblock++, (bh = bh->b_this_page) != head);
 
 	/* Check we have at least one buffer ready for i/o. */
@@ -749,7 +758,7 @@
 			struct buffer_head *tbh = arr[i];
 			lock_buffer(tbh);
 			tbh->b_end_io = end_buffer_read_mst_async;
-			mark_buffer_async(tbh, 1);
+			set_buffer_async(tbh);
 		}
 		/* Finally, start i/o on the buffers. */
 		for (i = 0; i < nr; i++)
@@ -761,7 +770,7 @@
 		SetPageUptodate(page);
 	else /* Signal synchronous i/o error. */
 		nr = -EIO;
-	UnlockPage(page);
+	unlock_page(page);
 	return nr;
 }
 
diff -Nru a/fs/ntfs/compress.c b/fs/ntfs/compress.c
--- a/fs/ntfs/compress.c	Tue Apr 30 17:10:25 2002
+++ b/fs/ntfs/compress.c	Tue Apr 30 17:10:25 2002
@@ -198,7 +198,7 @@
 			flush_dcache_page(dp);
 			kunmap(dp);
 			SetPageUptodate(dp);
-			UnlockPage(dp);
+			unlock_page(dp);
 			if (di == xpage)
 				*xpage_done = 1;
 			else
@@ -491,7 +491,7 @@
 		kfree(bhs);
 		kfree(pages);
 		SetPageError(page);
-		UnlockPage(page);
+		unlock_page(page);
 		ntfs_error(vol->sb, "Failed to allocate internal buffers.");
 		return -ENOMEM;
 	}
@@ -521,13 +521,13 @@
 			 * in and/or dirty or we would be losing data or at
 			 * least wasting our time.
 			 */
-			if (!PageDirty(page) && (!Page_Uptodate(page) ||
+			if (!PageDirty(page) && (!PageUptodate(page) ||
 					PageError(page))) {
 				ClearPageError(page);
 				kmap(page);
 				continue;
 			}
-			UnlockPage(page);
+			unlock_page(page);
 			page_cache_release(page);
 			pages[i] = NULL;
 		}
@@ -668,7 +668,7 @@
 				flush_dcache_page(page);
 				kunmap(page);
 				SetPageUptodate(page);
-				UnlockPage(page);
+				unlock_page(page);
 				if (cur_page == xpage)
 					xpage_done = 1;
 				else
@@ -738,7 +738,7 @@
 				flush_dcache_page(page);
 				kunmap(page);
 				SetPageUptodate(page);
-				UnlockPage(page);
+				unlock_page(page);
 				if (cur2_page == xpage)
 					xpage_done = 1;
 				else
@@ -775,7 +775,7 @@
 						SetPageError(page);
 					flush_dcache_page(page);
 					kunmap(page);
-					UnlockPage(page);
+					unlock_page(page);
 					if (prev_cur_page != xpage)
 						page_cache_release(page);
 					pages[prev_cur_page] = NULL;
@@ -806,7 +806,7 @@
 				SetPageError(page);
 			flush_dcache_page(page);
 			kunmap(page);
-			UnlockPage(page);
+			unlock_page(page);
 			if (cur_page != xpage)
 				page_cache_release(page);
 			pages[cur_page] = NULL;
@@ -853,7 +853,7 @@
 				SetPageError(page);
 			flush_dcache_page(page);
 			kunmap(page);
-			UnlockPage(page);
+			unlock_page(page);
 			if (i != xpage)
 				page_cache_release(page);
 		}
diff -Nru a/fs/ntfs/dir.c b/fs/ntfs/dir.c
--- a/fs/ntfs/dir.c	Tue Apr 30 17:10:25 2002
+++ b/fs/ntfs/dir.c	Tue Apr 30 17:10:25 2002
@@ -20,6 +20,7 @@
  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include <linux/smp_lock.h>
 #include "ntfs.h"
 
 /**
@@ -524,6 +525,7 @@
 	u8 *kaddr, *bmp, *index_end;
 	attr_search_context *ctx;
 
+	lock_kernel();
 	ntfs_debug("Entering for inode 0x%Lx, f_pos 0x%Lx.",
 			(unsigned long long)ndir->mft_no, filp->f_pos);
 	rc = err = 0;
@@ -792,6 +794,7 @@
 		ntfs_debug("filldir returned %i, f_pos 0x%Lx, returning 0.",
 				rc, filp->f_pos);
 #endif
+	unlock_kernel();
 	return 0;
 map_page_err_out:
 	ntfs_error(sb, "Reading index allocation data failed.");
diff -Nru a/fs/ntfs/ntfs.h b/fs/ntfs/ntfs.h
--- a/fs/ntfs/ntfs.h	Tue Apr 30 17:10:25 2002
+++ b/fs/ntfs/ntfs.h	Tue Apr 30 17:10:25 2002
@@ -188,9 +188,9 @@
 			(filler_t*)mapping->a_ops->readpage, NULL);
 
 	if (!IS_ERR(page)) {
-		wait_on_page(page);
+		wait_on_page_locked(page);
 		kmap(page);
-		if (Page_Uptodate(page) && !PageError(page))
+		if (PageUptodate(page) && !PageError(page))
 			return page;
 		ntfs_unmap_page(page);
 		return ERR_PTR(-EIO);
diff -Nru a/fs/ntfs/super.c b/fs/ntfs/super.c
--- a/fs/ntfs/super.c	Tue Apr 30 17:10:23 2002
+++ b/fs/ntfs/super.c	Tue Apr 30 17:10:23 2002
@@ -1214,8 +1214,8 @@
 					"page (index 0x%lx).", index - 1);
 			continue;
 		}
-		wait_on_page(page);
-		if (!Page_Uptodate(page)) {
+		wait_on_page_locked(page);
+		if (!PageUptodate(page)) {
 			ntfs_debug("Async read_cache_page() error. Skipping "
 					"page (index 0x%lx).", index - 1);
 			/* Ignore pages which errored asynchronously. */
@@ -1297,8 +1297,8 @@
 					"page (index 0x%lx).", index - 1);
 			continue;
 		}
-		wait_on_page(page);
-		if (!Page_Uptodate(page)) {
+		wait_on_page_locked(page);
+		if (!PageUptodate(page)) {
 			ntfs_debug("Async read_cache_page() error. Skipping "
 					"page (index 0x%lx).", index - 1);
 			/* Ignore pages which errored asynchronously. */
diff -Nru a/fs/open.c b/fs/open.c
--- a/fs/open.c	Tue Apr 30 17:10:23 2002
+++ b/fs/open.c	Tue Apr 30 17:10:23 2002
@@ -632,6 +632,7 @@
 			goto cleanup_file;
 	}
 
+	f->f_ra.ra_pages = *inode->i_mapping->ra_pages;
 	f->f_dentry = dentry;
 	f->f_vfsmnt = mnt;
 	f->f_pos = 0;
diff -Nru a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c
--- a/fs/openpromfs/inode.c	Tue Apr 30 17:10:25 2002
+++ b/fs/openpromfs/inode.c	Tue Apr 30 17:10:25 2002
@@ -756,12 +756,14 @@
 	u16 node;
 	char *p;
 	char buffer2[64];
+
+	lock_kernel();
 	
 	ino = inode->i_ino;
 	i = filp->f_pos;
 	switch (i) {
 	case 0:
-		if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0) return 0;
+		if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0) goto out;
 		i++;
 		filp->f_pos++;
 		/* fall thru */
@@ -769,7 +771,7 @@
 		if (filldir(dirent, "..", 2, i, 
 			(NODE(ino).parent == 0xffff) ? 
 			OPENPROM_ROOT_INO : NODE2INO(NODE(ino).parent), DT_DIR) < 0) 
-			return 0;
+			goto out;
 		i++;
 		filp->f_pos++;
 		/* fall thru */
@@ -782,17 +784,17 @@
 		}
 		while (node != 0xffff) {
 			if (prom_getname (nodes[node].node, buffer, 128) < 0)
-				return 0;
+				goto out;
 			if (filldir(dirent, buffer, strlen(buffer),
 				    filp->f_pos, NODE2INO(node), DT_DIR) < 0)
-				return 0;
+				goto out;
 			filp->f_pos++;
 			node = nodes[node].next;
 		}
 		j = NODEP2INO(NODE(ino).first_prop);
 		if (!i) {
 			if (filldir(dirent, ".node", 5, filp->f_pos, j, DT_REG) < 0)
-				return 0;
+				goto out;
 			filp->f_pos++;
 		} else
 			i--;
@@ -802,7 +804,7 @@
 				if (alias_names [i]) {
 					if (filldir (dirent, alias_names [i], 
 						strlen (alias_names [i]), 
-						filp->f_pos, j, DT_REG) < 0) return 0;
+						filp->f_pos, j, DT_REG) < 0) goto out; 
 					filp->f_pos++;
 				}
 			}
@@ -815,12 +817,14 @@
 				else {
 					if (filldir(dirent, p, strlen(p),
 						    filp->f_pos, j, DT_REG) < 0)
-						return 0;
+						goto out;
 					filp->f_pos++;
 				}
 			}
 		}
 	}
+out:
+	unlock_kernel();
 	return 0;
 }
 
diff -Nru a/fs/partitions/check.c b/fs/partitions/check.c
--- a/fs/partitions/check.c	Tue Apr 30 17:10:25 2002
+++ b/fs/partitions/check.c	Tue Apr 30 17:10:25 2002
@@ -432,8 +432,8 @@
 	page = read_cache_page(mapping, n/sect,
 			(filler_t *)mapping->a_ops->readpage, NULL);
 	if (!IS_ERR(page)) {
-		wait_on_page(page);
-		if (!Page_Uptodate(page))
+		wait_on_page_locked(page);
+		if (!PageUptodate(page))
 			goto fail;
 		if (PageError(page))
 			goto fail;
diff -Nru a/fs/proc/base.c b/fs/proc/base.c
--- a/fs/proc/base.c	Tue Apr 30 17:10:23 2002
+++ b/fs/proc/base.c	Tue Apr 30 17:10:23 2002
@@ -26,6 +26,7 @@
 #include <linux/seq_file.h>
 #include <linux/namespace.h>
 #include <linux/mm.h>
+#include <linux/smp_lock.h>
 
 /*
  * For hysterical raisins we keep the same inumbers as in the old procfs.
@@ -571,6 +572,8 @@
 	struct dentry *de;
 	struct vfsmount *mnt = NULL;
 
+	lock_kernel();
+
 	if (current->fsuid != inode->i_uid && !capable(CAP_DAC_OVERRIDE))
 		goto out;
 	error = proc_check_root(inode);
@@ -585,6 +588,7 @@
 	dput(de);
 	mntput(mnt);
 out:
+	unlock_kernel();
 	return error;
 }
 
@@ -665,38 +669,49 @@
 	int pid;
 	struct inode *inode = filp->f_dentry->d_inode;
 	struct pid_entry *p;
+	int ret = 0;
+
+	lock_kernel();
 
 	pid = proc_task(inode)->pid;
-	if (!pid)
-		return -ENOENT;
+	if (!pid) {
+		ret = -ENOENT;
+		goto out;
+	}
 	i = filp->f_pos;
 	switch (i) {
 		case 0:
 			if (filldir(dirent, ".", 1, i, inode->i_ino, DT_DIR) < 0)
-				return 0;
+				goto out;
 			i++;
 			filp->f_pos++;
 			/* fall through */
 		case 1:
 			if (filldir(dirent, "..", 2, i, PROC_ROOT_INO, DT_DIR) < 0)
-				return 0;
+				goto out;
 			i++;
 			filp->f_pos++;
 			/* fall through */
 		default:
 			i -= 2;
-			if (i>=sizeof(base_stuff)/sizeof(base_stuff[0]))
-				return 1;
+			if (i>=sizeof(base_stuff)/sizeof(base_stuff[0])) {
+				ret = 1;
+				goto out;
+			}
 			p = base_stuff + i;
 			while (p->name) {
 				if (filldir(dirent, p->name, p->len, filp->f_pos,
 					    fake_ino(pid, p->type), p->mode >> 12) < 0)
-					return 0;
+					goto out;
 				filp->f_pos++;
 				p++;
 			}
 	}
-	return 1;
+
+	ret = 1;
+out:
+	unlock_kernel();
+	return ret;
 }
 
 /* building an inode */
diff -Nru a/fs/proc/generic.c b/fs/proc/generic.c
--- a/fs/proc/generic.c	Tue Apr 30 17:10:25 2002
+++ b/fs/proc/generic.c	Tue Apr 30 17:10:25 2002
@@ -304,16 +304,21 @@
 	unsigned int ino;
 	int i;
 	struct inode *inode = filp->f_dentry->d_inode;
+	int ret = 0;
+
+	lock_kernel();
 
 	ino = inode->i_ino;
 	de = PDE(inode);
-	if (!de)
-		return -EINVAL;
+	if (!de) {
+		ret = -EINVAL;
+		goto out;
+	}
 	i = filp->f_pos;
 	switch (i) {
 		case 0:
 			if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
-				return 0;
+				goto out;
 			i++;
 			filp->f_pos++;
 			/* fall through */
@@ -321,7 +326,7 @@
 			if (filldir(dirent, "..", 2, i,
 				    parent_ino(filp->f_dentry),
 				    DT_DIR) < 0)
-				return 0;
+				goto out;
 			i++;
 			filp->f_pos++;
 			/* fall through */
@@ -329,8 +334,10 @@
 			de = de->subdir;
 			i -= 2;
 			for (;;) {
-				if (!de)
-					return 1;
+				if (!de) {
+					ret = 1;
+					goto out;
+				}
 				if (!i)
 					break;
 				de = de->next;
@@ -340,12 +347,14 @@
 			do {
 				if (filldir(dirent, de->name, de->namelen, filp->f_pos,
 					    de->low_ino, de->mode >> 12) < 0)
-					return 0;
+					goto out;
 				filp->f_pos++;
 				de = de->next;
 			} while (de);
 	}
-	return 1;
+	ret = 1;
+out:	unlock_kernel();
+	return ret;	
 }
 
 /*
diff -Nru a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
--- a/fs/proc/proc_misc.c	Tue Apr 30 17:10:23 2002
+++ b/fs/proc/proc_misc.c	Tue Apr 30 17:10:23 2002
@@ -129,14 +129,16 @@
 	struct sysinfo i;
 	int len;
 	int pg_size ;
+	struct page_state ps;
 
+	get_page_state(&ps);
 /*
  * display in kilobytes.
  */
 #define K(x) ((x) << (PAGE_SHIFT - 10))
 	si_meminfo(&i);
 	si_swapinfo(&i);
-	pg_size = atomic_read(&page_cache_size) - i.bufferram ;
+	pg_size = get_page_cache_size() - i.bufferram ;
 
 	/*
 	 * Tagged format, for easy grepping and expansion.
@@ -155,7 +157,9 @@
 		"LowTotal:     %8lu kB\n"
 		"LowFree:      %8lu kB\n"
 		"SwapTotal:    %8lu kB\n"
-		"SwapFree:     %8lu kB\n",
+		"SwapFree:     %8lu kB\n"
+		"Dirty:        %8lu kB\n"
+		"Locked:       %8lu kB\n",
 		K(i.totalram),
 		K(i.freeram),
 		K(i.sharedram),
@@ -169,7 +173,10 @@
 		K(i.totalram-i.totalhigh),
 		K(i.freeram-i.freehigh),
 		K(i.totalswap),
-		K(i.freeswap));
+		K(i.freeswap),
+		K(ps.nr_dirty),
+		K(ps.nr_locked)
+		);
 
 	return proc_calc_metrics(page, start, off, count, eof, len);
 #undef K
diff -Nru a/fs/proc/root.c b/fs/proc/root.c
--- a/fs/proc/root.c	Tue Apr 30 17:10:25 2002
+++ b/fs/proc/root.c	Tue Apr 30 17:10:25 2002
@@ -98,15 +98,22 @@
 	void * dirent, filldir_t filldir)
 {
 	unsigned int nr = filp->f_pos;
+	int ret;
+
+	lock_kernel();
 
 	if (nr < FIRST_PROCESS_ENTRY) {
 		int error = proc_readdir(filp, dirent, filldir);
-		if (error <= 0)
+		if (error <= 0) {
+			unlock_kernel();
 			return error;
+		}
 		filp->f_pos = FIRST_PROCESS_ENTRY;
 	}
 
-	return proc_pid_readdir(filp, dirent, filldir);
+	ret = proc_pid_readdir(filp, dirent, filldir);
+	unlock_kernel();
+	return ret;
 }
 
 /*
diff -Nru a/fs/qnx4/dir.c b/fs/qnx4/dir.c
--- a/fs/qnx4/dir.c	Tue Apr 30 17:10:23 2002
+++ b/fs/qnx4/dir.c	Tue Apr 30 17:10:23 2002
@@ -17,6 +17,7 @@
 #include <linux/fs.h>
 #include <linux/qnx4_fs.h>
 #include <linux/stat.h>
+#include <linux/smp_lock.h>
 
 
 static int qnx4_readdir(struct file *filp, void *dirent, filldir_t filldir)
@@ -33,6 +34,8 @@
 	QNX4DEBUG(("qnx4_readdir:i_size = %ld\n", (long) inode->i_size));
 	QNX4DEBUG(("filp->f_pos         = %ld\n", (long) filp->f_pos));
 
+	lock_kernel();
+
 	while (filp->f_pos < inode->i_size) {
 		blknum = qnx4_block_map( inode, filp->f_pos >> QNX4_BLOCK_SIZE_BITS );
 		bh = sb_bread(inode->i_sb, blknum);
@@ -63,7 +66,7 @@
 					}
 					if (filldir(dirent, de->di_fname, size, filp->f_pos, ino, DT_UNKNOWN) < 0) {
 						brelse(bh);
-						return 0;
+						goto out;
 					}
 				}
 			}
@@ -74,6 +77,8 @@
 	}
 	UPDATE_ATIME(inode);
 
+out:
+	unlock_kernel();
 	return 0;
 }
 
diff -Nru a/fs/ramfs/inode.c b/fs/ramfs/inode.c
--- a/fs/ramfs/inode.c	Tue Apr 30 17:10:25 2002
+++ b/fs/ramfs/inode.c	Tue Apr 30 17:10:25 2002
@@ -47,20 +47,20 @@
  */
 static int ramfs_readpage(struct file *file, struct page * page)
 {
-	if (!Page_Uptodate(page)) {
+	if (!PageUptodate(page)) {
 		memset(kmap(page), 0, PAGE_CACHE_SIZE);
 		kunmap(page);
 		flush_dcache_page(page);
 		SetPageUptodate(page);
 	}
-	UnlockPage(page);
+	unlock_page(page);
 	return 0;
 }
 
 static int ramfs_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to)
 {
 	void *addr = kmap(page);
-	if (!Page_Uptodate(page)) {
+	if (!PageUptodate(page)) {
 		memset(addr, 0, PAGE_CACHE_SIZE);
 		flush_dcache_page(page);
 		SetPageUptodate(page);
diff -Nru a/fs/readdir.c b/fs/readdir.c
--- a/fs/readdir.c	Tue Apr 30 17:10:25 2002
+++ b/fs/readdir.c	Tue Apr 30 17:10:25 2002
@@ -23,9 +23,7 @@
 	down(&inode->i_sem);
 	res = -ENOENT;
 	if (!IS_DEADDIR(inode)) {
-		lock_kernel();
 		res = file->f_op->readdir(file, buf, filler);
-		unlock_kernel();
 	}
 	up(&inode->i_sem);
 out:
diff -Nru a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c
--- a/fs/reiserfs/dir.c	Tue Apr 30 17:10:25 2002
+++ b/fs/reiserfs/dir.c	Tue Apr 30 17:10:25 2002
@@ -47,7 +47,9 @@
     loff_t next_pos;
     char small_buf[32] ; /* avoid kmalloc if we can */
     struct reiserfs_dir_entry de;
+    int ret = 0;
 
+    lock_kernel();
 
     reiserfs_check_lock_depth("readdir") ;
 
@@ -66,7 +68,8 @@
 	if (search_res == IO_ERROR) {
 	    // FIXME: we could just skip part of directory which could
 	    // not be read
-	    return -EIO;
+	    ret = -EIO;
+	    goto out;
 	}
 	entry_num = de.de_entry_num;
 	bh = de.de_bh;
@@ -118,7 +121,8 @@
 		    local_buf = reiserfs_kmalloc(d_reclen, GFP_NOFS, inode->i_sb) ;
 		    if (!local_buf) {
 			pathrelse (&path_to_entry);
-			return -ENOMEM ;
+			ret = -ENOMEM ;
+			goto out;
 		    }
 		    if (item_moved (&tmp_ih, &path_to_entry)) {
 			reiserfs_kfree(local_buf, d_reclen, inode->i_sb) ;
@@ -181,7 +185,9 @@
     pathrelse (&path_to_entry);
     reiserfs_check_path(&path_to_entry) ;
     UPDATE_ATIME(inode) ;
-    return 0;
+ out:
+    unlock_kernel();
+    return ret;
 }
 
 /* compose directory item containing "." and ".." entries (entries are
diff -Nru a/fs/reiserfs/do_balan.c b/fs/reiserfs/do_balan.c
--- a/fs/reiserfs/do_balan.c	Tue Apr 30 17:10:24 2002
+++ b/fs/reiserfs/do_balan.c	Tue Apr 30 17:10:24 2002
@@ -29,13 +29,27 @@
                                         is interrupting do_balance */
 #endif
 
+/*
+ * AKPM: The __mark_buffer_dirty() call here will not
+ * put the buffer on the dirty buffer LRU because we've just
+ * set BH_Dirty.  That's a thinko in reiserfs.
+ *
+ * I'm reluctant to "fix" this bug because that would change
+ * behaviour.  Using mark_buffer_dirty() here would make the
+ * buffer eligible for VM and periodic writeback, which may
+ * violate ordering constraints.  I'll just leave the code
+ * as-is by removing the __mark_buffer_dirty call altogether.
+ *
+ * Chris says this code has "probably never been run" anyway.
+ * It is due to go away.
+ */
 
 inline void do_balance_mark_leaf_dirty (struct tree_balance * tb, 
 					struct buffer_head * bh, int flag)
 {
     if (reiserfs_dont_log(tb->tb_sb)) {
-	if (!test_and_set_bit(BH_Dirty, &bh->b_state)) {
-	    __mark_buffer_dirty(bh) ;
+	if (!test_set_buffer_dirty(bh)) {
+//	    __mark_buffer_dirty(bh) ;
 	    tb->need_balance_dirty = 1;
 	}
     } else {
@@ -1211,7 +1225,7 @@
     bi.bi_parent = 0;
     bi.bi_position = 0;
     make_empty_node (&bi);
-    set_bit(BH_Uptodate, &first_b->b_state);
+    set_buffer_uptodate(first_b);
     tb->FEB[i] = 0;
     tb->used[i] = first_b;
 
@@ -1258,7 +1272,7 @@
     set_blkh_level( blkh, FREE_LEVEL );
     set_blkh_nr_item( blkh, 0 );
     
-    mark_buffer_clean (bh);
+    clear_buffer_dirty(bh);
     /* reiserfs_free_block is no longer schedule safe 
     reiserfs_free_block (tb->transaction_handle, tb->tb_sb, bh->b_blocknr);
     */
diff -Nru a/fs/reiserfs/file.c b/fs/reiserfs/file.c
--- a/fs/reiserfs/file.c	Tue Apr 30 17:10:23 2002
+++ b/fs/reiserfs/file.c	Tue Apr 30 17:10:23 2002
@@ -86,7 +86,6 @@
       BUG ();
 
   n_err = fsync_inode_buffers(p_s_inode) ;
-  n_err |= fsync_inode_data_buffers(p_s_inode);
   reiserfs_commit_for_inode(p_s_inode) ;
   unlock_kernel() ;
   return ( n_err < 0 ) ? -EIO : 0;
diff -Nru a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
--- a/fs/reiserfs/inode.c	Tue Apr 30 17:10:25 2002
+++ b/fs/reiserfs/inode.c	Tue Apr 30 17:10:25 2002
@@ -107,7 +107,7 @@
 static void add_to_flushlist(struct inode *inode, struct buffer_head *bh) {
     struct list_head *list = &(SB_JOURNAL(inode->i_sb)->j_dirty_buffers) ;
 
-    buffer_insert_list(bh, list) ;
+    buffer_insert_list(NULL, bh, list) ;
 }
 
 //
@@ -273,7 +273,7 @@
             kunmap(bh_result->b_page) ;
 	// We do not return -ENOENT if there is a hole but page is uptodate, because it means
 	// That there is some MMAPED data associated with it that is yet to be written to disk.
-	if ((args & GET_BLOCK_NO_HOLE) && !Page_Uptodate(bh_result->b_page) ) {
+	if ((args & GET_BLOCK_NO_HOLE) && !PageUptodate(bh_result->b_page) ) {
 	    return -ENOENT ;
 	}
         return 0 ;
@@ -295,7 +295,7 @@
 	} else 
 	    // We do not return -ENOENT if there is a hole but page is uptodate, because it means
 	    // That there is some MMAPED data associated with it that is yet to  be written to disk.
-	    if ((args & GET_BLOCK_NO_HOLE) && !Page_Uptodate(bh_result->b_page) ) {
+	    if ((args & GET_BLOCK_NO_HOLE) && !PageUptodate(bh_result->b_page) ) {
 	    ret = -ENOENT ;
 	    }
 
@@ -328,8 +328,8 @@
 	** read old data off disk.  Set the up to date bit on the buffer instead
 	** and jump to the end
 	*/
-	    if (Page_Uptodate(bh_result->b_page)) {
-		mark_buffer_uptodate(bh_result, 1);
+	    if (PageUptodate(bh_result->b_page)) {
+		set_buffer_uptodate(bh_result);
 		goto finished ;
     }
 
@@ -398,7 +398,7 @@
     pathrelse (&path);
     /* I _really_ doubt that you want it.  Chris? */
     map_bh(bh_result, inode->i_sb, 0);
-    mark_buffer_uptodate (bh_result, 1);
+    set_buffer_uptodate (bh_result);
     return 0;
 }
 
@@ -500,7 +500,7 @@
 
 unlock:
     if (tail_page != hole_page) {
-        UnlockPage(tail_page) ;
+        unlock_page(tail_page) ;
 	page_cache_release(tail_page) ;
     }
 out:
@@ -653,7 +653,7 @@
 		reiserfs_restore_prepared_buffer(inode->i_sb, bh) ;
 		goto research;
 	    }
-	    bh_result->b_state |= (1UL << BH_New);
+	    set_buffer_new(bh_result);
 	    put_block_num(item, pos_in_item, allocated_block_nr) ;
             unfm_ptr = allocated_block_nr;
 	    journal_mark_dirty (&th, inode->i_sb, bh);
@@ -705,7 +705,7 @@
 		   allocated block for that */
 		unp = cpu_to_le32 (allocated_block_nr);
 		set_block_dev_mapped (bh_result, allocated_block_nr, inode);
-		bh_result->b_state |= (1UL << BH_New);
+		set_buffer_new(bh_result);
 		done = 1;
 	    }
 	    tmp_key = key; // ;)
@@ -761,7 +761,7 @@
 		reiserfs_free_block (&th, allocated_block_nr);
 		goto failure;
 	    }
-	    /* it is important the mark_buffer_uptodate is done after
+	    /* it is important the set_buffer_uptodate is done after
 	    ** the direct2indirect.  The buffer might contain valid
 	    ** data newer than the data on disk (read by readpage, changed,
 	    ** and then sent here by writepage).  direct2indirect needs
@@ -769,7 +769,7 @@
 	    ** if the data in unbh needs to be replaced with data from
 	    ** the disk
 	    */
-	    mark_buffer_uptodate (unbh, 1);
+	    set_buffer_uptodate (unbh);
 
 	    /* we've converted the tail, so we must 
 	    ** flush unbh before the transaction commits
@@ -779,7 +779,13 @@
 	    /* mark it dirty now to prevent commit_write from adding
 	    ** this buffer to the inode's dirty buffer list
 	    */
-	    __mark_buffer_dirty(unbh) ;
+		/*
+		 * AKPM: changed __mark_buffer_dirty to mark_buffer_dirty().
+		 * It's still atomic, but it sets the page dirty too,
+		 * which makes it eligible for writeback at any time by the
+		 * VM (which was also the case with __mark_buffer_dirty())
+		 */
+	    mark_buffer_dirty(unbh) ;
 		  
 	    //inode->i_blocks += inode->i_sb->s_blocksize / 512;
 	    //mark_tail_converted (inode);
@@ -803,7 +809,7 @@
 		   block for that */
 		un.unfm_nodenum = cpu_to_le32 (allocated_block_nr);
 		set_block_dev_mapped (bh_result, allocated_block_nr, inode);
-		bh_result->b_state |= (1UL << BH_New);
+		set_buffer_new(bh_result);
 		done = 1;
 	    } else {
 		/* paste hole to the indirect item */
@@ -1716,7 +1722,7 @@
     return error ;
 
 unlock:
-    UnlockPage(page) ;
+    unlock_page(page) ;
     page_cache_release(page) ;
     return error ;
 }
@@ -1788,7 +1794,7 @@
 	        mark_buffer_dirty(bh) ;
 	    }
 	}
-	UnlockPage(page) ;
+	unlock_page(page) ;
 	page_cache_release(page) ;
     }
 
@@ -1845,7 +1851,7 @@
 	    goto out ;
 	}
 	set_block_dev_mapped(bh_result, get_block_num(item,pos_in_item),inode);
-        mark_buffer_uptodate(bh_result, 1);
+        set_buffer_uptodate(bh_result);
     } else if (is_direct_le_ih(ih)) {
         char *p ; 
         p = page_address(bh_result->b_page) ;
@@ -1865,7 +1871,7 @@
 	journal_mark_dirty(&th, inode->i_sb, bh) ;
 	bytes_copied += copy_size ;
 	set_block_dev_mapped(bh_result, 0, inode);
-        mark_buffer_uptodate(bh_result, 1);
+        set_buffer_uptodate(bh_result);
 
 	/* are there still bytes left? */
         if (bytes_copied < bh_result->b_size && 
@@ -1915,8 +1921,8 @@
 	** later on in the call chain will be cleaning it.  So, we
 	** clean the buffer here, it still gets written either way.
 	*/
-	clear_bit(BH_Dirty, &bh->b_state) ;
-	set_bit(BH_Uptodate, &bh->b_state) ;
+	clear_buffer_dirty(bh) ;
+	set_buffer_uptodate(bh) ;
 	submit_bh(WRITE, bh) ;
     }
 }
@@ -1984,24 +1990,30 @@
 	block++ ;
     } while(bh != head) ;
 
+    if (!partial)
+        SetPageUptodate(page) ;
+    BUG_ON(PageWriteback(page));
+    SetPageWriteback(page);
+    unlock_page(page);
+
     /* if this page only had a direct item, it is very possible for
     ** nr == 0 without there being any kind of error.
     */
     if (nr) {
         submit_bh_for_writepage(arr, nr) ;
     } else {
-        UnlockPage(page) ;
+        end_page_writeback(page) ;
     }
-    if (!partial)
-        SetPageUptodate(page) ;
 
     return 0 ;
 
 fail:
     if (nr) {
+        SetPageWriteback(page);
+        unlock_page(page);
         submit_bh_for_writepage(arr, nr) ;
     } else {
-        UnlockPage(page) ;
+        unlock_page(page) ;
     }
     ClearPageUptodate(page) ;
     return error ;
diff -Nru a/fs/reiserfs/ioctl.c b/fs/reiserfs/ioctl.c
--- a/fs/reiserfs/ioctl.c	Tue Apr 30 17:10:25 2002
+++ b/fs/reiserfs/ioctl.c	Tue Apr 30 17:10:25 2002
@@ -83,7 +83,7 @@
     kunmap(page) ; /* mapped by prepare_write */
 
 out_unlock:
-    UnlockPage(page) ;
+    unlock_page(page) ;
     page_cache_release(page) ;
 
 out:
diff -Nru a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
--- a/fs/reiserfs/journal.c	Tue Apr 30 17:10:23 2002
+++ b/fs/reiserfs/journal.c	Tue Apr 30 17:10:23 2002
@@ -123,10 +123,8 @@
 ** more details.
 */
 static int reiserfs_clean_and_file_buffer(struct buffer_head *bh) {
-  if (bh) {
-    clear_bit(BH_Dirty, &bh->b_state) ;
-    refile_buffer(bh) ;
-  }
+  if (bh)
+    clear_buffer_dirty(bh);
   return 0 ;
 }
 
@@ -849,7 +847,7 @@
     jh->j_last_flush_trans_id = cpu_to_le32(trans_id) ;
     jh->j_first_unflushed_offset = cpu_to_le32(offset) ;
     jh->j_mount_id = cpu_to_le32(SB_JOURNAL(p_s_sb)->j_mount_id) ;
-    set_bit(BH_Dirty, &(SB_JOURNAL(p_s_sb)->j_header_bh->b_state)) ;
+    set_buffer_dirty(SB_JOURNAL(p_s_sb)->j_header_bh) ;
     ll_rw_block(WRITE, 1, &(SB_JOURNAL(p_s_sb)->j_header_bh)) ;
     wait_on_buffer((SB_JOURNAL(p_s_sb)->j_header_bh)) ; 
     if (!buffer_uptodate(SB_JOURNAL(p_s_sb)->j_header_bh)) {
@@ -895,7 +893,10 @@
         reiserfs_warning("clm-2084: pinned buffer %lu:%s sent to disk\n",
 	                 bh->b_blocknr, bdevname(bh->b_bdev)) ;
     }
-    mark_buffer_uptodate(bh, uptodate) ;
+    if (uptodate)
+    	set_buffer_uptodate(bh) ;
+    else
+    	clear_buffer_uptodate(bh) ;
     unlock_buffer(bh) ;
     put_bh(bh) ;
 }
@@ -904,7 +905,7 @@
     get_bh(bh) ;
     bh->b_end_io = reiserfs_end_buffer_io_sync ;
     mark_buffer_notjournal_new(bh) ;
-    clear_bit(BH_Dirty, &bh->b_state) ;
+    clear_buffer_dirty(bh) ;
     submit_bh(WRITE, bh) ;
 }
 
@@ -1079,7 +1080,6 @@
 	if (!buffer_uptodate(cn->bh)) {
 	  reiserfs_panic(s, "journal-949: buffer write failed\n") ;
 	}
-	refile_buffer(cn->bh) ;
         brelse(cn->bh) ;
       }
       cn = cn->next ;
@@ -1568,12 +1568,12 @@
       return -1 ;
     }
     memcpy(real_blocks[i]->b_data, log_blocks[i]->b_data, real_blocks[i]->b_size) ;
-    mark_buffer_uptodate(real_blocks[i], 1) ;
+    set_buffer_uptodate(real_blocks[i]) ;
     brelse(log_blocks[i]) ;
   }
   /* flush out the real blocks */
   for (i = 0 ; i < le32_to_cpu(desc->j_len) ; i++) {
-    set_bit(BH_Dirty, &(real_blocks[i]->b_state)) ;
+    set_buffer_dirty(real_blocks[i]) ;
     ll_rw_block(WRITE, 1, real_blocks + i) ;
   }
   for (i = 0 ; i < le32_to_cpu(desc->j_len) ; i++) {
@@ -2392,7 +2392,7 @@
   }
 
   if (buffer_dirty(bh)) {
-    clear_bit(BH_Dirty, &bh->b_state) ;
+    clear_buffer_dirty(bh) ;
   }
 
   if (buffer_journaled(bh)) { /* must double check after getting lock */
@@ -2982,7 +2982,7 @@
   rs = SB_DISK_SUPER_BLOCK(p_s_sb) ;
   /* setup description block */
   d_bh = journ_getblk(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + SB_JOURNAL(p_s_sb)->j_start) ; 
-  mark_buffer_uptodate(d_bh, 1) ;
+  set_buffer_uptodate(d_bh) ;
   desc = (struct reiserfs_journal_desc *)(d_bh)->b_data ;
   memset(desc, 0, sizeof(struct reiserfs_journal_desc)) ;
   memcpy(desc->j_magic, JOURNAL_DESC_MAGIC, 8) ;
@@ -2994,7 +2994,7 @@
   commit = (struct reiserfs_journal_commit *)c_bh->b_data ;
   memset(commit, 0, sizeof(struct reiserfs_journal_commit)) ;
   commit->j_trans_id = cpu_to_le32(SB_JOURNAL(p_s_sb)->j_trans_id) ;
-  mark_buffer_uptodate(c_bh, 1) ;
+  set_buffer_uptodate(c_bh) ;
 
   /* init this journal list */
   atomic_set(&(SB_JOURNAL_LIST(p_s_sb)[SB_JOURNAL_LIST_INDEX(p_s_sb)].j_older_commits_done), 0) ;
@@ -3082,7 +3082,7 @@
       struct buffer_head *tmp_bh ;
       tmp_bh =  journ_getblk(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + 
 		       ((cur_write_start + jindex) % SB_ONDISK_JOURNAL_SIZE(p_s_sb))) ;
-      mark_buffer_uptodate(tmp_bh, 1) ;
+      set_buffer_uptodate(tmp_bh) ;
       memcpy(tmp_bh->b_data, cn->bh->b_data, cn->bh->b_size) ;  
       jindex++ ;
     } else {
@@ -3125,7 +3125,7 @@
   SB_JOURNAL_LIST_INDEX(p_s_sb) = jindex ;
 
   /* write any buffers that must hit disk before this commit is done */
-  fsync_buffers_list(&(SB_JOURNAL(p_s_sb)->j_dirty_buffers)) ;
+  fsync_buffers_list(NULL, &(SB_JOURNAL(p_s_sb)->j_dirty_buffers)) ;
 
   /* honor the flush and async wishes from the caller */
   if (flush) {
diff -Nru a/fs/reiserfs/prints.c b/fs/reiserfs/prints.c
--- a/fs/reiserfs/prints.c	Tue Apr 30 17:10:25 2002
+++ b/fs/reiserfs/prints.c	Tue Apr 30 17:10:25 2002
@@ -138,8 +138,9 @@
 
 static void sprintf_buffer_head (char * buf, struct buffer_head * bh) 
 {
-  sprintf (buf, "dev %s, size %d, blocknr %ld, count %d, list %d, state 0x%lx, page %p, (%s, %s, %s)",
-	   bdevname (bh->b_bdev), bh->b_size, bh->b_blocknr, atomic_read (&(bh->b_count)), bh->b_list,
+  sprintf (buf, "dev %s, size %d, blocknr %ld, count %d, state 0x%lx, page %p, (%s, %s, %s)",
+	   bdevname (bh->b_bdev), bh->b_size, bh->b_blocknr,
+	   atomic_read (&(bh->b_count)),
 	   bh->b_state, bh->b_page,
 	   buffer_uptodate (bh) ? "UPTODATE" : "!UPTODATE",
 	   buffer_dirty (bh) ? "DIRTY" : "CLEAN",
diff -Nru a/fs/reiserfs/resize.c b/fs/reiserfs/resize.c
--- a/fs/reiserfs/resize.c	Tue Apr 30 17:10:25 2002
+++ b/fs/reiserfs/resize.c	Tue Apr 30 17:10:25 2002
@@ -116,7 +116,7 @@
 		reiserfs_test_and_set_le_bit(0, bitmap[i]->b_data);
 
 		mark_buffer_dirty(bitmap[i]) ;
-		mark_buffer_uptodate(bitmap[i], 1);
+		set_buffer_uptodate(bitmap[i]);
 		ll_rw_block(WRITE, 1, bitmap + i);
 		wait_on_buffer(bitmap[i]);
 	    }	
diff -Nru a/fs/reiserfs/tail_conversion.c b/fs/reiserfs/tail_conversion.c
--- a/fs/reiserfs/tail_conversion.c	Tue Apr 30 17:10:25 2002
+++ b/fs/reiserfs/tail_conversion.c	Tue Apr 30 17:10:25 2002
@@ -106,7 +106,7 @@
 	** this avoids overwriting good data from writepage() with old data
 	** from the disk or buffer cache
 	*/
-	if (buffer_uptodate(unbh) || Page_Uptodate(unbh->b_page)) {
+	if (buffer_uptodate(unbh) || PageUptodate(unbh->b_page)) {
 	    up_to_date_bh = NULL ;
 	} else {
 	    up_to_date_bh = unbh ;
@@ -141,11 +141,11 @@
     if (buffer_journaled(bh) || buffer_journal_dirty(bh)) {
       BUG() ;
     }
-    mark_buffer_clean(bh) ;
+    clear_buffer_dirty(bh) ;
     lock_buffer(bh) ;
-    clear_bit(BH_Mapped, &bh->b_state) ;
-    clear_bit(BH_Req, &bh->b_state) ;
-    clear_bit(BH_New, &bh->b_state) ;
+    clear_buffer_mapped(bh) ;
+    clear_buffer_req(bh) ;
+    clear_buffer_new(bh);
     bh->b_bdev = NULL;
     unlock_buffer(bh) ;
   }
diff -Nru a/fs/romfs/inode.c b/fs/romfs/inode.c
--- a/fs/romfs/inode.c	Tue Apr 30 17:10:25 2002
+++ b/fs/romfs/inode.c	Tue Apr 30 17:10:25 2002
@@ -273,13 +273,15 @@
 	int stored = 0;
 	char fsname[ROMFS_MAXFN];	/* XXX dynamic? */
 
+	lock_kernel();
+	
 	maxoff = i->i_sb->u.romfs_sb.s_maxsize;
 
 	offset = filp->f_pos;
 	if (!offset) {
 		offset = i->i_ino & ROMFH_MASK;
 		if (romfs_copyfrom(i, &ri, offset, ROMFH_SIZE) <= 0)
-			return stored;
+			goto out;
 		offset = ntohl(ri.spec) & ROMFH_MASK;
 	}
 
@@ -288,17 +290,17 @@
 		if (!offset || offset >= maxoff) {
 			offset = maxoff;
 			filp->f_pos = offset;
-			return stored;
+			goto out;
 		}
 		filp->f_pos = offset;
 
 		/* Fetch inode info */
 		if (romfs_copyfrom(i, &ri, offset, ROMFH_SIZE) <= 0)
-			return stored;
+			goto out;
 
 		j = romfs_strnlen(i, offset+ROMFH_SIZE, sizeof(fsname)-1);
 		if (j < 0)
-			return stored;
+			goto out;
 
 		fsname[j]=0;
 		romfs_copyfrom(i, fsname, offset+ROMFH_SIZE, j);
@@ -309,11 +311,14 @@
 			ino = ntohl(ri.spec);
 		if (filldir(dirent, fsname, j, offset, ino,
 			    romfs_dtype_table[nextfh & ROMFH_TYPE]) < 0) {
-			return stored;
+			goto out;
 		}
 		stored++;
 		offset = nextfh & ROMFH_MASK;
 	}
+out:
+	unlock_kernel();
+	return stored;
 }
 
 static struct dentry *
@@ -432,7 +437,7 @@
 	}
 	flush_dcache_page(page);
 
-	UnlockPage(page);
+	unlock_page(page);
 
 	kunmap(page);
 err_out:
diff -Nru a/fs/smbfs/cache.c b/fs/smbfs/cache.c
--- a/fs/smbfs/cache.c	Tue Apr 30 17:10:25 2002
+++ b/fs/smbfs/cache.c	Tue Apr 30 17:10:25 2002
@@ -37,7 +37,7 @@
 	if (!page)
 		goto out;
 
-	if (!Page_Uptodate(page))
+	if (!PageUptodate(page))
 		goto out_unlock;
 
 	cache = kmap(page);
@@ -46,7 +46,7 @@
 	kunmap(page);
 	SetPageUptodate(page);
 out_unlock:
-	UnlockPage(page);
+	unlock_page(page);
 	page_cache_release(page);
 out:
 	return;
@@ -172,7 +172,7 @@
 		if (ctl.page) {
 			kunmap(ctl.page);
 			SetPageUptodate(ctl.page);
-			UnlockPage(ctl.page);
+			unlock_page(ctl.page);
 			page_cache_release(ctl.page);
 		}
 		ctl.cache = NULL;
diff -Nru a/fs/smbfs/dir.c b/fs/smbfs/dir.c
--- a/fs/smbfs/dir.c	Tue Apr 30 17:10:25 2002
+++ b/fs/smbfs/dir.c	Tue Apr 30 17:10:25 2002
@@ -75,6 +75,9 @@
 		DENTRY_PATH(dentry),  (int) filp->f_pos);
 
 	result = 0;
+
+	lock_kernel();
+
 	switch ((unsigned int) filp->f_pos) {
 	case 0:
 		if (filldir(dirent, ".", 1, 0, dir->i_ino, DT_DIR) < 0)
@@ -102,9 +105,9 @@
 	ctl.cache = cache = kmap(page);
 	ctl.head  = cache->head;
 
-	if (!Page_Uptodate(page) || !ctl.head.eof) {
+	if (!PageUptodate(page) || !ctl.head.eof) {
 		VERBOSE("%s/%s, page uptodate=%d, eof=%d\n",
-			 DENTRY_PATH(dentry), Page_Uptodate(page),ctl.head.eof);
+			 DENTRY_PATH(dentry), PageUptodate(page),ctl.head.eof);
 		goto init_cache;
 	}
 
@@ -136,7 +139,7 @@
 			if (!ctl.page)
 				goto invalid_cache;
 			ctl.cache = kmap(ctl.page);
-			if (!Page_Uptodate(ctl.page))
+			if (!PageUptodate(ctl.page))
 				goto invalid_cache;
 		}
 		while (ctl.idx < SMB_DIRCACHE_SIZE) {
@@ -162,7 +165,7 @@
 		if (ctl.page) {
 			kunmap(ctl.page);
 			SetPageUptodate(ctl.page);
-			UnlockPage(ctl.page);
+			unlock_page(ctl.page);
 			page_cache_release(ctl.page);
 			ctl.page = NULL;
 		}
@@ -172,7 +175,7 @@
 invalid_cache:
 	if (ctl.page) {
 		kunmap(ctl.page);
-		UnlockPage(ctl.page);
+		unlock_page(ctl.page);
 		page_cache_release(ctl.page);
 		ctl.page = NULL;
 	}
@@ -197,16 +200,17 @@
 		cache->head = ctl.head;
 		kunmap(page);
 		SetPageUptodate(page);
-		UnlockPage(page);
+		unlock_page(page);
 		page_cache_release(page);
 	}
 	if (ctl.page) {
 		kunmap(ctl.page);
 		SetPageUptodate(ctl.page);
-		UnlockPage(ctl.page);
+		unlock_page(ctl.page);
 		page_cache_release(ctl.page);
 	}
 out:
+	unlock_kernel();
 	return result;
 }
 
diff -Nru a/fs/smbfs/file.c b/fs/smbfs/file.c
--- a/fs/smbfs/file.c	Tue Apr 30 17:10:25 2002
+++ b/fs/smbfs/file.c	Tue Apr 30 17:10:25 2002
@@ -94,7 +94,7 @@
 
 io_error:
 	kunmap(page);
-	UnlockPage(page);
+	unlock_page(page);
 	return result;
 }
 
@@ -199,7 +199,7 @@
 	get_page(page);
 	err = smb_writepage_sync(inode, page, 0, offset);
 	SetPageUptodate(page);
-	UnlockPage(page);
+	unlock_page(page);
 	put_page(page);
 	return err;
 }
@@ -354,7 +354,8 @@
 		/* We must flush any dirty pages now as we won't be able to
 		   write anything after close. mmap can trigger this.
 		   "openers" should perhaps include mmap'ers ... */
-		filemap_fdatasync(inode->i_mapping);
+		filemap_fdatawait(inode->i_mapping);
+		filemap_fdatawrite(inode->i_mapping);
 		filemap_fdatawait(inode->i_mapping);
 		smb_close(inode);
 	}
diff -Nru a/fs/smbfs/inode.c b/fs/smbfs/inode.c
--- a/fs/smbfs/inode.c	Tue Apr 30 17:10:23 2002
+++ b/fs/smbfs/inode.c	Tue Apr 30 17:10:23 2002
@@ -645,7 +645,8 @@
 			DENTRY_PATH(dentry),
 			(long) inode->i_size, (long) attr->ia_size);
 
-		filemap_fdatasync(inode->i_mapping);
+		filemap_fdatawait(inode->i_mapping);
+		filemap_fdatawrite(inode->i_mapping);
 		filemap_fdatawait(inode->i_mapping);
 
 		error = smb_open(dentry, O_WRONLY);
diff -Nru a/fs/smbfs/proc.c b/fs/smbfs/proc.c
--- a/fs/smbfs/proc.c	Tue Apr 30 17:10:23 2002
+++ b/fs/smbfs/proc.c	Tue Apr 30 17:10:23 2002
@@ -17,6 +17,7 @@
 #include <linux/dcache.h>
 #include <linux/dirent.h>
 #include <linux/nls.h>
+#include <linux/smp_lock.h>
 
 #include <linux/smb_fs.h>
 #include <linux/smbno.h>
@@ -1906,6 +1907,8 @@
 
 	VERBOSE("%s/%s\n", DENTRY_PATH(dir));
 
+	lock_kernel();
+
 	smb_lock_server(server);
 
 	first = 1;
@@ -2012,6 +2015,7 @@
 
 unlock_return:
 	smb_unlock_server(server);
+	unlock_kernel();
 	return result;
 }
 
@@ -2172,6 +2176,8 @@
 		len:	1,
 	};
 
+	lock_kernel();
+
 	/*
 	 * use info level 1 for older servers that don't do 260
 	 */
@@ -2357,6 +2363,7 @@
 
 unlock_return:
 	smb_unlock_server(server);
+	unlock_kernel();
 	return result;
 }
 
diff -Nru a/fs/sysv/balloc.c b/fs/sysv/balloc.c
--- a/fs/sysv/balloc.c	Tue Apr 30 17:10:25 2002
+++ b/fs/sysv/balloc.c	Tue Apr 30 17:10:25 2002
@@ -19,9 +19,8 @@
  *  This file contains code for allocating/freeing blocks.
  */
 
-#include <linux/fs.h>
-#include <linux/sysv_fs.h>
 #include <linux/locks.h>
+#include "sysv.h"
 
 /* We don't trust the value of
    sb->sv_sbd2->s_tfree = *sb->sv_free_blocks
@@ -31,7 +30,7 @@
 {
 	char *bh_data = bh->b_data;
 
-	if (sb->sv_type == FSTYPE_SYSV4)
+	if (SYSV_SB(sb)->s_type == FSTYPE_SYSV4)
 		return (u32*)(bh_data+4);
 	else
 		return (u32*)(bh_data+2);
@@ -41,28 +40,29 @@
 
 void sysv_free_block(struct super_block * sb, u32 nr)
 {
+	struct sysv_sb_info * sbi = SYSV_SB(sb);
 	struct buffer_head * bh;
-	u32 *blocks = sb->sv_bcache;
+	u32 *blocks = sbi->s_bcache;
 	unsigned count;
-	unsigned block = fs32_to_cpu(sb, nr);
+	unsigned block = fs32_to_cpu(sbi, nr);
 
 	/*
 	 * This code does not work at all for AFS (it has a bitmap
 	 * free list).  As AFS is supposed to be read-only no one
 	 * should call this for an AFS filesystem anyway...
 	 */
-	if (sb->sv_type == FSTYPE_AFS)
+	if (sbi->s_type == FSTYPE_AFS)
 		return;
 
-	if (block < sb->sv_firstdatazone || block >= sb->sv_nzones) {
+	if (block < sbi->s_firstdatazone || block >= sbi->s_nzones) {
 		printk("sysv_free_block: trying to free block not in datazone\n");
 		return;
 	}
 
 	lock_super(sb);
-	count = fs16_to_cpu(sb, *sb->sv_bcache_count);
+	count = fs16_to_cpu(sbi, *sbi->s_bcache_count);
 
-	if (count > sb->sv_flc_size) {
+	if (count > sbi->s_flc_size) {
 		printk("sysv_free_block: flc_count > flc_size\n");
 		unlock_super(sb);
 		return;
@@ -71,8 +71,8 @@
 	 * into this block being freed, ditto if it's completely empty
 	 * (applies only on Coherent).
 	 */
-	if (count == sb->sv_flc_size || count == 0) {
-		block += sb->sv_block_base;
+	if (count == sbi->s_flc_size || count == 0) {
+		block += sbi->s_block_base;
 		bh = sb_getblk(sb, block);
 		if (!bh) {
 			printk("sysv_free_block: getblk() failed\n");
@@ -80,42 +80,43 @@
 			return;
 		}
 		memset(bh->b_data, 0, sb->s_blocksize);
-		*(u16*)bh->b_data = cpu_to_fs16(sb, count);
+		*(u16*)bh->b_data = cpu_to_fs16(sbi, count);
 		memcpy(get_chunk(sb,bh), blocks, count * sizeof(sysv_zone_t));
 		mark_buffer_dirty(bh);
-		mark_buffer_uptodate(bh, 1);
+		set_buffer_uptodate(bh);
 		brelse(bh);
 		count = 0;
 	}
-	sb->sv_bcache[count++] = nr;
+	sbi->s_bcache[count++] = nr;
 
-	*sb->sv_bcache_count = cpu_to_fs16(sb, count);
-	fs32_add(sb, sb->sv_free_blocks, 1);
+	*sbi->s_bcache_count = cpu_to_fs16(sbi, count);
+	fs32_add(sbi, sbi->s_free_blocks, 1);
 	dirty_sb(sb);
 	unlock_super(sb);
 }
 
 u32 sysv_new_block(struct super_block * sb)
 {
+	struct sysv_sb_info *sbi = SYSV_SB(sb);
 	unsigned int block;
 	u32 nr;
 	struct buffer_head * bh;
 	unsigned count;
 
 	lock_super(sb);
-	count = fs16_to_cpu(sb, *sb->sv_bcache_count);
+	count = fs16_to_cpu(sbi, *sbi->s_bcache_count);
 
 	if (count == 0) /* Applies only to Coherent FS */
 		goto Enospc;
-	nr = sb->sv_bcache[--count];
+	nr = sbi->s_bcache[--count];
 	if (nr == 0)  /* Applies only to Xenix FS, SystemV FS */
 		goto Enospc;
 
-	block = fs32_to_cpu(sb, nr);
+	block = fs32_to_cpu(sbi, nr);
 
-	*sb->sv_bcache_count = cpu_to_fs16(sb, count);
+	*sbi->s_bcache_count = cpu_to_fs16(sbi, count);
 
-	if (block < sb->sv_firstdatazone || block >= sb->sv_nzones) {
+	if (block < sbi->s_firstdatazone || block >= sbi->s_nzones) {
 		printk("sysv_new_block: new block %d is not in data zone\n",
 			block);
 		goto Enospc;
@@ -124,26 +125,26 @@
 	if (count == 0) { /* the last block continues the free list */
 		unsigned count;
 
-		block += sb->sv_block_base;
+		block += sbi->s_block_base;
 		if (!(bh = sb_bread(sb, block))) {
 			printk("sysv_new_block: cannot read free-list block\n");
 			/* retry this same block next time */
-			*sb->sv_bcache_count = cpu_to_fs16(sb, 1);
+			*sbi->s_bcache_count = cpu_to_fs16(sbi, 1);
 			goto Enospc;
 		}
-		count = fs16_to_cpu(sb, *(u16*)bh->b_data);
-		if (count > sb->sv_flc_size) {
+		count = fs16_to_cpu(sbi, *(u16*)bh->b_data);
+		if (count > sbi->s_flc_size) {
 			printk("sysv_new_block: free-list block with >flc_size entries\n");
 			brelse(bh);
 			goto Enospc;
 		}
-		*sb->sv_bcache_count = cpu_to_fs16(sb, count);
-		memcpy(sb->sv_bcache, get_chunk(sb, bh),
+		*sbi->s_bcache_count = cpu_to_fs16(sbi, count);
+		memcpy(sbi->s_bcache, get_chunk(sb, bh),
 				count * sizeof(sysv_zone_t));
 		brelse(bh);
 	}
 	/* Now the free list head in the superblock is valid again. */
-	fs32_add(sb, sb->sv_free_blocks, -1);
+	fs32_add(sbi, sbi->s_free_blocks, -1);
 	dirty_sb(sb);
 	unlock_super(sb);
 	return nr;
@@ -155,6 +156,7 @@
 
 unsigned long sysv_count_free_blocks(struct super_block * sb)
 {
+	struct sysv_sb_info * sbi = SYSV_SB(sb);
 	int sb_count;
 	int count;
 	struct buffer_head * bh = NULL;
@@ -167,21 +169,21 @@
 	 * free list).  As AFS is supposed to be read-only we just
 	 * lie and say it has no free block at all.
 	 */
-	if (sb->sv_type == FSTYPE_AFS)
+	if (sbi->s_type == FSTYPE_AFS)
 		return 0;
 
 	lock_super(sb);
-	sb_count = fs32_to_cpu(sb, *sb->sv_free_blocks);
+	sb_count = fs32_to_cpu(sbi, *sbi->s_free_blocks);
 
 	if (0)
 		goto trust_sb;
 
 	/* this causes a lot of disk traffic ... */
 	count = 0;
-	n = fs16_to_cpu(sb, *sb->sv_bcache_count);
-	blocks = sb->sv_bcache;
+	n = fs16_to_cpu(sbi, *sbi->s_bcache_count);
+	blocks = sbi->s_bcache;
 	while (1) {
-		if (n > sb->sv_flc_size)
+		if (n > sbi->s_flc_size)
 			goto E2big;
 		block = 0;
 		while (n && (block = blocks[--n]) != 0)
@@ -189,17 +191,17 @@
 		if (block == 0)
 			break;
 
-		block = fs32_to_cpu(sb, block);
+		block = fs32_to_cpu(sbi, block);
 		if (bh)
 			brelse(bh);
 
-		if (block < sb->sv_firstdatazone || block >= sb->sv_nzones)
+		if (block < sbi->s_firstdatazone || block >= sbi->s_nzones)
 			goto Einval;
-		block += sb->sv_block_base;
+		block += sbi->s_block_base;
 		bh = sb_bread(sb, block);
 		if (!bh)
 			goto Eio;
-		n = fs16_to_cpu(sb, *(u16*)bh->b_data);
+		n = fs16_to_cpu(sbi, *(u16*)bh->b_data);
 		blocks = get_chunk(sb, bh);
 	}
 	if (bh)
@@ -228,7 +230,7 @@
 	printk("sysv_count_free_blocks: free block count was %d, "
 		"correcting to %d\n", sb_count, count);
 	if (!(sb->s_flags & MS_RDONLY)) {
-		*sb->sv_free_blocks = cpu_to_fs32(sb, count);
+		*sbi->s_free_blocks = cpu_to_fs32(sbi, count);
 		dirty_sb(sb);
 	}
 	goto done;
diff -Nru a/fs/sysv/dir.c b/fs/sysv/dir.c
--- a/fs/sysv/dir.c	Tue Apr 30 17:10:25 2002
+++ b/fs/sysv/dir.c	Tue Apr 30 17:10:25 2002
@@ -13,9 +13,9 @@
  *  SystemV/Coherent directory handling functions
  */
 
-#include <linux/fs.h>
-#include <linux/sysv_fs.h>
 #include <linux/pagemap.h>
+#include <linux/smp_lock.h>
+#include "sysv.h"
 
 static int sysv_readdir(struct file *, void *, filldir_t);
 
@@ -42,13 +42,10 @@
 	int err = 0;
 
 	page->mapping->a_ops->commit_write(NULL, page, from, to);
-	if (IS_SYNC(dir)) {
-		int err2;
-		err = writeout_one_page(page);
-		err2 = waitfor_one_page(page);
-		if (err == 0)
-			err = err2;
-	}
+	if (IS_SYNC(dir))
+		err = write_one_page(page, 1);
+	else
+		unlock_page(page);
 	return err;
 }
 
@@ -58,9 +55,9 @@
 	struct page *page = read_cache_page(mapping, n,
 				(filler_t*)mapping->a_ops->readpage, NULL);
 	if (!IS_ERR(page)) {
-		wait_on_page(page);
+		wait_on_page_locked(page);
 		kmap(page);
-		if (!Page_Uptodate(page))
+		if (!PageUptodate(page))
 			goto fail;
 	}
 	return page;
@@ -79,6 +76,8 @@
 	unsigned long n = pos >> PAGE_CACHE_SHIFT;
 	unsigned long npages = dir_pages(inode);
 
+	lock_kernel();
+
 	pos = (pos + SYSV_DIRSIZE-1) & ~(SYSV_DIRSIZE-1);
 	if (pos >= inode->i_size)
 		goto done;
@@ -104,7 +103,8 @@
 
 			over = filldir(dirent, name, strnlen(name,SYSV_NAMELEN),
 					(n<<PAGE_CACHE_SHIFT) | offset,
-					fs16_to_cpu(sb, de->inode), DT_UNKNOWN);
+					fs16_to_cpu(SYSV_SB(sb), de->inode),
+					DT_UNKNOWN);
 			if (over) {
 				dir_put_page(page);
 				goto done;
@@ -116,6 +116,7 @@
 done:
 	filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset;
 	UPDATE_ATIME(inode);
+	unlock_kernel();
 	return 0;
 }
 
@@ -228,16 +229,17 @@
 		goto out_unlock;
 	memcpy (de->name, name, namelen);
 	memset (de->name + namelen, 0, SYSV_DIRSIZE - namelen - 2);
-	de->inode = cpu_to_fs16(inode->i_sb, inode->i_ino);
+	de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), inode->i_ino);
 	err = dir_commit_chunk(page, from, to);
 	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
 	mark_inode_dirty(dir);
-out_unlock:
-	UnlockPage(page);
 out_page:
 	dir_put_page(page);
 out:
 	return err;
+out_unlock:
+	unlock_page(page);
+	goto out_page;
 }
 
 int sysv_delete_entry(struct sysv_dir_entry *de, struct page *page)
@@ -255,7 +257,6 @@
 		BUG();
 	de->inode = 0;
 	err = dir_commit_chunk(page, from, to);
-	UnlockPage(page);
 	dir_put_page(page);
 	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
 	mark_inode_dirty(inode);
@@ -273,22 +274,23 @@
 	if (!page)
 		return -ENOMEM;
 	err = mapping->a_ops->prepare_write(NULL, page, 0, 2 * SYSV_DIRSIZE);
-	if (err)
+	if (err) {
+		unlock_page(page);
 		goto fail;
+	}
 
 	base = (char*)page_address(page);
 	memset(base, 0, PAGE_CACHE_SIZE);
 
 	de = (struct sysv_dir_entry *) base;
-	de->inode = cpu_to_fs16(inode->i_sb, inode->i_ino);
+	de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), inode->i_ino);
 	strcpy(de->name,".");
 	de++;
-	de->inode = cpu_to_fs16(inode->i_sb, dir->i_ino);
+	de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), dir->i_ino);
 	strcpy(de->name,"..");
 
 	err = dir_commit_chunk(page, 0, 2 * SYSV_DIRSIZE);
 fail:
-	UnlockPage(page);
 	page_cache_release(page);
 	return err;
 }
@@ -321,7 +323,8 @@
 			if (de->name[0] != '.')
 				goto not_empty;
 			if (!de->name[1]) {
-				if (de->inode == cpu_to_fs16(sb, inode->i_ino))
+				if (de->inode == cpu_to_fs16(SYSV_SB(sb),
+							inode->i_ino))
 					continue;
 				goto not_empty;
 			}
@@ -350,9 +353,8 @@
 	err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
 	if (err)
 		BUG();
-	de->inode = cpu_to_fs16(inode->i_sb, inode->i_ino);
+	de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), inode->i_ino);
 	err = dir_commit_chunk(page, from, to);
-	UnlockPage(page);
 	dir_put_page(page);
 	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
 	mark_inode_dirty(dir);
@@ -377,7 +379,7 @@
 	ino_t res = 0;
 	
 	if (de) {
-		res = fs16_to_cpu(dentry->d_sb, de->inode);
+		res = fs16_to_cpu(SYSV_SB(dentry->d_sb), de->inode);
 		dir_put_page(page);
 	}
 	return res;
diff -Nru a/fs/sysv/file.c b/fs/sysv/file.c
--- a/fs/sysv/file.c	Tue Apr 30 17:10:25 2002
+++ b/fs/sysv/file.c	Tue Apr 30 17:10:25 2002
@@ -13,8 +13,7 @@
  *  SystemV/Coherent regular file handling primitives
  */
 
-#include <linux/fs.h>
-#include <linux/sysv_fs.h>
+#include "sysv.h"
 
 /*
  * We have mostly NULLs here: the current defaults are OK for
@@ -38,7 +37,6 @@
 	int err;
 
 	err = fsync_inode_buffers(inode);
-	err |= fsync_inode_data_buffers(inode);
 	if (!(inode->i_state & I_DIRTY))
 		return err;
 	if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
diff -Nru a/fs/sysv/ialloc.c b/fs/sysv/ialloc.c
--- a/fs/sysv/ialloc.c	Tue Apr 30 17:10:24 2002
+++ b/fs/sysv/ialloc.c	Tue Apr 30 17:10:24 2002
@@ -20,12 +20,11 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/sysv_fs.h>
 #include <linux/stddef.h>
 #include <linux/stat.h>
 #include <linux/string.h>
 #include <linux/locks.h>
+#include "sysv.h"
 
 /* We don't trust the value of
    sb->sv_sbd2->s_tinode = *sb->sv_sb_total_free_inodes
@@ -37,33 +36,38 @@
 static inline sysv_ino_t *
 sv_sb_fic_inode(struct super_block * sb, unsigned int i)
 {
-	if (sb->sv_bh1 == sb->sv_bh2)
-		return &sb->sv_sb_fic_inodes[i];
+	struct sysv_sb_info *sbi = SYSV_SB(sb);
+
+	if (sbi->s_bh1 == sbi->s_bh2)
+		return &sbi->s_sb_fic_inodes[i];
 	else {
 		/* 512 byte Xenix FS */
 		unsigned int offset = offsetof(struct xenix_super_block, s_inode[i]);
 		if (offset < 512)
-			return (sysv_ino_t*)(sb->sv_sbd1 + offset);
+			return (sysv_ino_t*)(sbi->s_sbd1 + offset);
 		else
-			return (sysv_ino_t*)(sb->sv_sbd2 + offset);
+			return (sysv_ino_t*)(sbi->s_sbd2 + offset);
 	}
 }
 
 struct sysv_inode *
 sysv_raw_inode(struct super_block *sb, unsigned ino, struct buffer_head **bh)
 {
+	struct sysv_sb_info *sbi = SYSV_SB(sb);
 	struct sysv_inode *res;
-	int block = sb->sv_firstinodezone + sb->sv_block_base;
-	block += (ino-1) >> sb->sv_inodes_per_block_bits;
+	int block = sbi->s_firstinodezone + sbi->s_block_base;
+
+	block += (ino-1) >> sbi->s_inodes_per_block_bits;
 	*bh = sb_bread(sb, block);
 	if (!*bh)
 		return NULL;
-	res = (struct sysv_inode *) (*bh)->b_data;
-	return res + ((ino-1) & sb->sv_inodes_per_block_1);
+	res = (struct sysv_inode *)(*bh)->b_data;
+	return res + ((ino-1) & sbi->s_inodes_per_block_1);
 }
 
 static int refill_free_cache(struct super_block *sb)
 {
+	struct sysv_sb_info *sbi = SYSV_SB(sb);
 	struct buffer_head * bh;
 	struct sysv_inode * raw_inode;
 	int i = 0, ino;
@@ -72,13 +76,13 @@
 	raw_inode = sysv_raw_inode(sb, ino, &bh);
 	if (!raw_inode)
 		goto out;
-	while (ino <= sb->sv_ninodes) {
+	while (ino <= sbi->s_ninodes) {
 		if (raw_inode->i_mode == 0 && raw_inode->i_nlink == 0) {
-			*sv_sb_fic_inode(sb,i++) = cpu_to_fs16(sb, ino);
-			if (i == sb->sv_fic_size)
+			*sv_sb_fic_inode(sb,i++) = cpu_to_fs16(SYSV_SB(sb), ino);
+			if (i == sbi->s_fic_size)
 				break;
 		}
-		if ((ino++ & sb->sv_inodes_per_block_1) == 0) {
+		if ((ino++ & sbi->s_inodes_per_block_1) == 0) {
 			brelse(bh);
 			raw_inode = sysv_raw_inode(sb, ino, &bh);
 			if (!raw_inode)
@@ -93,7 +97,8 @@
 
 void sysv_free_inode(struct inode * inode)
 {
-	struct super_block * sb;
+	struct super_block *sb = inode->i_sb;
+	struct sysv_sb_info *sbi = SYSV_SB(sb);
 	unsigned int ino;
 	struct buffer_head * bh;
 	struct sysv_inode * raw_inode;
@@ -101,7 +106,7 @@
 
 	sb = inode->i_sb;
 	ino = inode->i_ino;
-	if (ino <= SYSV_ROOT_INO || ino > sb->sv_ninodes) {
+	if (ino <= SYSV_ROOT_INO || ino > sbi->s_ninodes) {
 		printk("sysv_free_inode: inode 0,1,2 or nonexistent inode\n");
 		return;
 	}
@@ -113,12 +118,12 @@
 		return;
 	}
 	lock_super(sb);
-	count = fs16_to_cpu(sb, *sb->sv_sb_fic_count);
-	if (count < sb->sv_fic_size) {
-		*sv_sb_fic_inode(sb,count++) = cpu_to_fs16(sb, ino);
-		*sb->sv_sb_fic_count = cpu_to_fs16(sb, count);
+	count = fs16_to_cpu(sbi, *sbi->s_sb_fic_count);
+	if (count < sbi->s_fic_size) {
+		*sv_sb_fic_inode(sb,count++) = cpu_to_fs16(sbi, ino);
+		*sbi->s_sb_fic_count = cpu_to_fs16(sbi, count);
 	}
-	fs16_add(sb, sb->sv_sb_total_free_inodes, 1);
+	fs16_add(sbi, sbi->s_sb_total_free_inodes, 1);
 	dirty_sb(sb);
 	memset(raw_inode, 0, sizeof(struct sysv_inode));
 	mark_buffer_dirty(bh);
@@ -128,18 +133,18 @@
 
 struct inode * sysv_new_inode(const struct inode * dir, mode_t mode)
 {
-	struct inode * inode;
-	struct super_block * sb;
+	struct super_block *sb = dir->i_sb;
+	struct sysv_sb_info *sbi = SYSV_SB(sb);
+	struct inode *inode;
 	u16 ino;
 	unsigned count;
 
-	sb = dir->i_sb;
 	inode = new_inode(sb);
 	if (!inode)
 		return ERR_PTR(-ENOMEM);
 
 	lock_super(sb);
-	count = fs16_to_cpu(sb, *sb->sv_sb_fic_count);
+	count = fs16_to_cpu(sbi, *sbi->s_sb_fic_count);
 	if (count == 0 || (*sv_sb_fic_inode(sb,count-1) == 0)) {
 		count = refill_free_cache(sb);
 		if (count == 0) {
@@ -150,8 +155,8 @@
 	}
 	/* Now count > 0. */
 	ino = *sv_sb_fic_inode(sb,--count);
-	*sb->sv_sb_fic_count = cpu_to_fs16(sb, count);
-	fs16_add(sb, sb->sv_sb_total_free_inodes, -1);
+	*sbi->s_sb_fic_count = cpu_to_fs16(sbi, count);
+	fs16_add(sbi, sbi->s_sb_total_free_inodes, -1);
 	dirty_sb(sb);
 	
 	if (dir->i_mode & S_ISGID) {
@@ -162,7 +167,7 @@
 		inode->i_gid = current->fsgid;
 
 	inode->i_uid = current->fsuid;
-	inode->i_ino = fs16_to_cpu(sb, ino);
+	inode->i_ino = fs16_to_cpu(sbi, ino);
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 	inode->i_blocks = inode->i_blksize = 0;
 	memset(SYSV_I(inode)->i_data, 0, sizeof(SYSV_I(inode)->i_data));
@@ -180,13 +185,14 @@
 
 unsigned long sysv_count_free_inodes(struct super_block * sb)
 {
+	struct sysv_sb_info *sbi = SYSV_SB(sb);
 	struct buffer_head * bh;
 	struct sysv_inode * raw_inode;
 	int ino, count, sb_count;
 
 	lock_super(sb);
 
-	sb_count = fs16_to_cpu(sb, *sb->sv_sb_total_free_inodes);
+	sb_count = fs16_to_cpu(sbi, *sbi->s_sb_total_free_inodes);
 
 	if (0)
 		goto trust_sb;
@@ -197,10 +203,10 @@
 	raw_inode = sysv_raw_inode(sb, ino, &bh);
 	if (!raw_inode)
 		goto Eio;
-	while (ino <= sb->sv_ninodes) {
+	while (ino <= sbi->s_ninodes) {
 		if (raw_inode->i_mode == 0 && raw_inode->i_nlink == 0)
 			count++;
-		if ((ino++ & sb->sv_inodes_per_block_1) == 0) {
+		if ((ino++ & sbi->s_inodes_per_block_1) == 0) {
 			brelse(bh);
 			raw_inode = sysv_raw_inode(sb, ino, &bh);
 			if (!raw_inode)
@@ -220,7 +226,7 @@
 		"free inode count was %d, correcting to %d\n",
 		sb_count, count);
 	if (!(sb->s_flags & MS_RDONLY)) {
-		*sb->sv_sb_total_free_inodes = cpu_to_fs16(sb, count);
+		*sbi->s_sb_total_free_inodes = cpu_to_fs16(SYSV_SB(sb), count);
 		dirty_sb(sb);
 	}
 	goto out;
diff -Nru a/fs/sysv/inode.c b/fs/sysv/inode.c
--- a/fs/sysv/inode.c	Tue Apr 30 17:10:23 2002
+++ b/fs/sysv/inode.c	Tue Apr 30 17:10:23 2002
@@ -21,56 +21,68 @@
  *  the superblock.
  */
 
-#include <linux/fs.h>
-#include <linux/sysv_fs.h>
 #include <linux/locks.h>
 #include <linux/smp_lock.h>
 #include <linux/highuid.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <asm/byteorder.h>
+#include "sysv.h"
 
 /* This is only called on sync() and umount(), when s_dirt=1. */
 static void sysv_write_super(struct super_block *sb)
 {
+	struct sysv_sb_info *sbi = SYSV_SB(sb);
+	unsigned long time = CURRENT_TIME, old_time;
+
 	lock_kernel();
-	if (!(sb->s_flags & MS_RDONLY)) {
-		/* If we are going to write out the super block,
-		   then attach current time stamp.
-		   But if the filesystem was marked clean, keep it clean. */
-		unsigned long time = CURRENT_TIME;
-		unsigned long old_time = fs32_to_cpu(sb, *sb->sv_sb_time);
-		if (sb->sv_type == FSTYPE_SYSV4)
-			if (*sb->sv_sb_state == cpu_to_fs32(sb, 0x7c269d38 - old_time))
-				*sb->sv_sb_state = cpu_to_fs32(sb, 0x7c269d38 - time);
-		*sb->sv_sb_time = cpu_to_fs32(sb, time);
-		mark_buffer_dirty(sb->sv_bh2);
+	if (sb->s_flags & MS_RDONLY)
+		goto clean;
+
+	/*
+	 * If we are going to write out the super block,
+	 * then attach current time stamp.
+	 * But if the filesystem was marked clean, keep it clean.
+	 */
+	old_time = fs32_to_cpu(sbi, *sbi->s_sb_time);
+	if (sbi->s_type == FSTYPE_SYSV4) {
+		if (*sbi->s_sb_state == cpu_to_fs32(sbi, 0x7c269d38 - old_time))
+			*sbi->s_sb_state = cpu_to_fs32(sbi, 0x7c269d38 - time);
+		*sbi->s_sb_time = cpu_to_fs32(sbi, time);
+		mark_buffer_dirty(sbi->s_bh2);
 	}
+clean:
 	sb->s_dirt = 0;
 	unlock_kernel();
 }
 
 static void sysv_put_super(struct super_block *sb)
 {
+	struct sysv_sb_info *sbi = SYSV_SB(sb);
+
 	if (!(sb->s_flags & MS_RDONLY)) {
 		/* XXX ext2 also updates the state here */
-		mark_buffer_dirty(sb->sv_bh1);
-		if (sb->sv_bh1 != sb->sv_bh2)
-			mark_buffer_dirty(sb->sv_bh2);
+		mark_buffer_dirty(sbi->s_bh1);
+		if (sbi->s_bh1 != sbi->s_bh2)
+			mark_buffer_dirty(sbi->s_bh2);
 	}
 
-	brelse(sb->sv_bh1);
-	if (sb->sv_bh1 != sb->sv_bh2)
-		brelse(sb->sv_bh2);
+	brelse(sbi->s_bh1);
+	if (sbi->s_bh1 != sbi->s_bh2)
+		brelse(sbi->s_bh2);
+
+	kfree(sbi);
 }
 
 static int sysv_statfs(struct super_block *sb, struct statfs *buf)
 {
+	struct sysv_sb_info *sbi = SYSV_SB(sb);
+
 	buf->f_type = sb->s_magic;
 	buf->f_bsize = sb->s_blocksize;
-	buf->f_blocks = sb->sv_ndatazones;
+	buf->f_blocks = sbi->s_ndatazones;
 	buf->f_bavail = buf->f_bfree = sysv_count_free_blocks(sb);
-	buf->f_files = sb->sv_ninodes;
+	buf->f_files = sbi->s_ninodes;
 	buf->f_ffree = sysv_count_free_inodes(sb);
 	buf->f_namelen = SYSV_NAMELEN;
 	return 0;
@@ -79,15 +91,15 @@
 /* 
  * NXI <-> N0XI for PDP, XIN <-> XIN0 for le32, NIX <-> 0NIX for be32
  */
-static inline void read3byte(struct super_block *sb,
+static inline void read3byte(struct sysv_sb_info *sbi,
 	unsigned char * from, unsigned char * to)
 {
-	if (sb->sv_bytesex == BYTESEX_PDP) {
+	if (sbi->s_bytesex == BYTESEX_PDP) {
 		to[0] = from[0];
 		to[1] = 0;
 		to[2] = from[1];
 		to[3] = from[2];
-	} else if (sb->sv_bytesex == BYTESEX_LE) {
+	} else if (sbi->s_bytesex == BYTESEX_LE) {
 		to[0] = from[0];
 		to[1] = from[1];
 		to[2] = from[2];
@@ -100,14 +112,14 @@
 	}
 }
 
-static inline void write3byte(struct super_block *sb,
+static inline void write3byte(struct sysv_sb_info *sbi,
 	unsigned char * from, unsigned char * to)
 {
-	if (sb->sv_bytesex == BYTESEX_PDP) {
+	if (sbi->s_bytesex == BYTESEX_PDP) {
 		to[0] = from[0];
 		to[1] = from[2];
 		to[2] = from[3];
-	} else if (sb->sv_bytesex == BYTESEX_LE) {
+	} else if (sbi->s_bytesex == BYTESEX_LE) {
 		to[0] = from[0];
 		to[1] = from[1];
 		to[2] = from[2];
@@ -146,6 +158,7 @@
 static void sysv_read_inode(struct inode *inode)
 {
 	struct super_block * sb = inode->i_sb;
+	struct sysv_sb_info * sbi = SYSV_SB(sb);
 	struct buffer_head * bh;
 	struct sysv_inode * raw_inode;
 	struct sysv_inode_info * si;
@@ -153,7 +166,7 @@
 	dev_t rdev = 0;
 
 	ino = inode->i_ino;
-	if (!ino || ino > sb->sv_ninodes) {
+	if (!ino || ino > sbi->s_ninodes) {
 		printk("Bad inode number on dev %s: %d is out of range\n",
 		       inode->i_sb->s_id, ino);
 		goto bad_inode;
@@ -165,23 +178,23 @@
 		goto bad_inode;
 	}
 	/* SystemV FS: kludge permissions if ino==SYSV_ROOT_INO ?? */
-	inode->i_mode = fs16_to_cpu(sb, raw_inode->i_mode);
-	inode->i_uid = (uid_t)fs16_to_cpu(sb, raw_inode->i_uid);
-	inode->i_gid = (gid_t)fs16_to_cpu(sb, raw_inode->i_gid);
-	inode->i_nlink = fs16_to_cpu(sb, raw_inode->i_nlink);
-	inode->i_size = fs32_to_cpu(sb, raw_inode->i_size);
-	inode->i_atime = fs32_to_cpu(sb, raw_inode->i_atime);
-	inode->i_mtime = fs32_to_cpu(sb, raw_inode->i_mtime);
-	inode->i_ctime = fs32_to_cpu(sb, raw_inode->i_ctime);
+	inode->i_mode = fs16_to_cpu(sbi, raw_inode->i_mode);
+	inode->i_uid = (uid_t)fs16_to_cpu(sbi, raw_inode->i_uid);
+	inode->i_gid = (gid_t)fs16_to_cpu(sbi, raw_inode->i_gid);
+	inode->i_nlink = fs16_to_cpu(sbi, raw_inode->i_nlink);
+	inode->i_size = fs32_to_cpu(sbi, raw_inode->i_size);
+	inode->i_atime = fs32_to_cpu(sbi, raw_inode->i_atime);
+	inode->i_mtime = fs32_to_cpu(sbi, raw_inode->i_mtime);
+	inode->i_ctime = fs32_to_cpu(sbi, raw_inode->i_ctime);
 	inode->i_blocks = inode->i_blksize = 0;
 
 	si = SYSV_I(inode);
 	for (block = 0; block < 10+1+1+1; block++)
-		read3byte(sb, &raw_inode->i_a.i_addb[3*block],
-			(unsigned char*)&si->i_data[block]);
+		read3byte(sbi, &raw_inode->i_data[3*block],
+				(u8 *)&si->i_data[block]);
 	brelse(bh);
 	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
-		rdev = (u16)fs32_to_cpu(sb, si->i_data[0]);
+		rdev = (u16)fs32_to_cpu(sbi, si->i_data[0]);
 	si->i_dir_start_lookup = 0;
 	sysv_set_inode(inode, rdev);
 	return;
@@ -194,13 +207,14 @@
 static struct buffer_head * sysv_update_inode(struct inode * inode)
 {
 	struct super_block * sb = inode->i_sb;
+	struct sysv_sb_info * sbi = SYSV_SB(sb);
 	struct buffer_head * bh;
 	struct sysv_inode * raw_inode;
 	struct sysv_inode_info * si;
 	unsigned int ino, block;
 
 	ino = inode->i_ino;
-	if (!ino || ino > sb->sv_ninodes) {
+	if (!ino || ino > sbi->s_ninodes) {
 		printk("Bad inode number on dev %s: %d is out of range\n",
 		       inode->i_sb->s_id, ino);
 		return 0;
@@ -211,21 +225,21 @@
 		return 0;
 	}
 
-	raw_inode->i_mode = cpu_to_fs16(sb, inode->i_mode);
-	raw_inode->i_uid = cpu_to_fs16(sb, fs_high2lowuid(inode->i_uid));
-	raw_inode->i_gid = cpu_to_fs16(sb, fs_high2lowgid(inode->i_gid));
-	raw_inode->i_nlink = cpu_to_fs16(sb, inode->i_nlink);
-	raw_inode->i_size = cpu_to_fs32(sb, inode->i_size);
-	raw_inode->i_atime = cpu_to_fs32(sb, inode->i_atime);
-	raw_inode->i_mtime = cpu_to_fs32(sb, inode->i_mtime);
-	raw_inode->i_ctime = cpu_to_fs32(sb, inode->i_ctime);
+	raw_inode->i_mode = cpu_to_fs16(sbi, inode->i_mode);
+	raw_inode->i_uid = cpu_to_fs16(sbi, fs_high2lowuid(inode->i_uid));
+	raw_inode->i_gid = cpu_to_fs16(sbi, fs_high2lowgid(inode->i_gid));
+	raw_inode->i_nlink = cpu_to_fs16(sbi, inode->i_nlink);
+	raw_inode->i_size = cpu_to_fs32(sbi, inode->i_size);
+	raw_inode->i_atime = cpu_to_fs32(sbi, inode->i_atime);
+	raw_inode->i_mtime = cpu_to_fs32(sbi, inode->i_mtime);
+	raw_inode->i_ctime = cpu_to_fs32(sbi, inode->i_ctime);
 
 	si = SYSV_I(inode);
 	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
-		si->i_data[0] = cpu_to_fs32(sb, kdev_t_to_nr(inode->i_rdev));
+		si->i_data[0] = cpu_to_fs32(sbi, kdev_t_to_nr(inode->i_rdev));
 	for (block = 0; block < 10+1+1+1; block++)
-		write3byte(sb, (unsigned char*)&si->i_data[block],
-			&raw_inode->i_a.i_addb[3*block]);
+		write3byte(sbi, (u8 *)&si->i_data[block],
+			&raw_inode->i_data[3*block]);
 	mark_buffer_dirty(bh);
 	return bh;
 }
diff -Nru a/fs/sysv/itree.c b/fs/sysv/itree.c
--- a/fs/sysv/itree.c	Tue Apr 30 17:10:25 2002
+++ b/fs/sysv/itree.c	Tue Apr 30 17:10:25 2002
@@ -5,10 +5,8 @@
  *  AV, Sep--Dec 2000
  */
 
-#include <linux/fs.h>
-#include <linux/sysv_fs.h>
 #include <linux/locks.h>
-#include <linux/smp_lock.h>
+#include "sysv.h"
 
 enum {DIRECT = 10, DEPTH = 4};	/* Have triple indirect */
 
@@ -24,9 +22,10 @@
 static int block_to_path(struct inode *inode, long block, int offsets[DEPTH])
 {
 	struct super_block *sb = inode->i_sb;
-	int ptrs_bits = sb->sv_ind_per_block_bits;
-	unsigned long	indirect_blocks = sb->sv_ind_per_block,
-			double_blocks = sb->sv_ind_per_block_2;
+	struct sysv_sb_info *sbi = SYSV_SB(sb);
+	int ptrs_bits = sbi->s_ind_per_block_bits;
+	unsigned long	indirect_blocks = sbi->s_ind_per_block,
+			double_blocks = sbi->s_ind_per_block_2;
 	int n = 0;
 
 	if (block < 0) {
@@ -51,9 +50,9 @@
 	return n;
 }
 
-static inline int block_to_cpu(struct super_block *sb, u32 nr)
+static inline int block_to_cpu(struct sysv_sb_info *sbi, u32 nr)
 {
-	return sb->sv_block_base + fs32_to_cpu(sb, nr);
+	return sbi->s_block_base + fs32_to_cpu(sbi, nr);
 }
 
 typedef struct {
@@ -62,6 +61,8 @@
 	struct buffer_head *bh;
 } Indirect;
 
+static rwlock_t pointers_lock = RW_LOCK_UNLOCKED;
+
 static inline void add_chain(Indirect *p, struct buffer_head *bh, u32 *v)
 {
 	p->key = *(p->p = v);
@@ -91,23 +92,26 @@
 	struct buffer_head *bh;
 
 	*err = 0;
-	add_chain (chain, NULL, SYSV_I(inode)->i_data + *offsets);
+	add_chain(chain, NULL, SYSV_I(inode)->i_data + *offsets);
 	if (!p->key)
 		goto no_block;
 	while (--depth) {
-		int block = block_to_cpu(sb, p->key);
+		int block = block_to_cpu(SYSV_SB(sb), p->key);
 		bh = sb_bread(sb, block);
 		if (!bh)
 			goto failure;
+		read_lock(&pointers_lock);
 		if (!verify_chain(chain, p))
 			goto changed;
 		add_chain(++p, bh, (u32*)bh->b_data + *++offsets);
+		read_unlock(&pointers_lock);
 		if (!p->key)
-		goto no_block;
+			goto no_block;
 	}
 	return NULL;
 
 changed:
+	read_unlock(&pointers_lock);
 	brelse(bh);
 	*err = -EAGAIN;
 	goto no_block;
@@ -138,14 +142,14 @@
 		 * Get buffer_head for parent block, zero it out and set 
 		 * the pointer to new one, then send parent to disk.
 		 */
-		parent = block_to_cpu(inode->i_sb, branch[n-1].key);
+		parent = block_to_cpu(SYSV_SB(inode->i_sb), branch[n-1].key);
 		bh = sb_getblk(inode->i_sb, parent);
 		lock_buffer(bh);
 		memset(bh->b_data, 0, blocksize);
 		branch[n].bh = bh;
 		branch[n].p = (u32*) bh->b_data + offsets[n];
 		*branch[n].p = branch[n].key;
-		mark_buffer_uptodate(bh, 1);
+		set_buffer_uptodate(bh);
 		unlock_buffer(bh);
 		dirty_indirect(bh, inode);
 	}
@@ -166,12 +170,14 @@
 				int num)
 {
 	int i;
-	/* Verify that place we are splicing to is still there and vacant */
 
+	/* Verify that place we are splicing to is still there and vacant */
+	write_lock(&pointers_lock);
 	if (!verify_chain(chain, where-1) || *where->p)
 		goto changed;
-
 	*where->p = where->key;
+	write_unlock(&pointers_lock);
+
 	inode->i_ctime = CURRENT_TIME;
 
 	/* had we spliced it onto indirect block? */
@@ -185,6 +191,7 @@
 	return 0;
 
 changed:
+	write_unlock(&pointers_lock);
 	for (i = 1; i < num; i++)
 		bforget(where[i].bh);
 	for (i = 0; i < num; i++)
@@ -205,14 +212,14 @@
 	if (depth == 0)
 		goto out;
 
-	lock_kernel();
 reread:
 	partial = get_branch(inode, depth, offsets, chain, &err);
 
 	/* Simplest case - block found, no allocation needed */
 	if (!partial) {
 got_it:
-		map_bh(bh_result, sb, block_to_cpu(sb, chain[depth-1].key));
+		map_bh(bh_result, sb, block_to_cpu(SYSV_SB(sb),
+					chain[depth-1].key));
 		/* Clean up and exit */
 		partial = chain+depth-1; /* the whole chain */
 		goto cleanup;
@@ -225,7 +232,6 @@
 			brelse(partial->bh);
 			partial--;
 		}
-		unlock_kernel();
 out:
 		return err;
 	}
@@ -246,7 +252,7 @@
 	if (splice_branch(inode, chain, partial, left) < 0)
 		goto changed;
 
-	bh_result->b_state |= (1UL << BH_New);
+	set_buffer_new(bh_result);
 	goto got_it;
 
 changed:
@@ -277,6 +283,8 @@
 	*top = 0;
 	for (k = depth; k > 1 && !offsets[k-1]; k--)
 		;
+
+	write_lock(&pointers_lock);
 	partial = get_branch(inode, k, offsets, chain, &err);
 	if (!partial)
 		partial = chain + k-1;
@@ -284,8 +292,10 @@
 	 * If the branch acquired continuation since we've looked at it -
 	 * fine, it should all survive and (new) top doesn't belong to us.
 	 */
-	if (!partial->key && *partial->p)
+	if (!partial->key && *partial->p) {
+		write_unlock(&pointers_lock);
 		goto no_top;
+	}
 	for (p=partial; p>chain && all_zeroes((u32*)p->bh->b_data,p->p); p--)
 		;
 	/*
@@ -300,8 +310,9 @@
 		*top = *p->p;
 		*p->p = 0;
 	}
+	write_unlock(&pointers_lock);
 
-	while(partial > p) {
+	while (partial > p) {
 		brelse(partial->bh);
 		partial--;
 	}
@@ -333,7 +344,7 @@
 			if (!nr)
 				continue;
 			*p = 0;
-			block = block_to_cpu(sb, nr);
+			block = block_to_cpu(SYSV_SB(sb), nr);
 			bh = sb_bread(sb, block);
 			if (!bh)
 				continue;
@@ -372,8 +383,6 @@
 	if (n == 0)
 		return;
 
-	lock_kernel();
-
 	if (n == 1) {
 		free_data(inode, i_data+offsets[0], i_data + DIRECT);
 		goto do_indirects;
@@ -412,7 +421,6 @@
 		sysv_sync_inode (inode);
 	else
 		mark_inode_dirty(inode);
-	unlock_kernel();
 }
 
 static int sysv_writepage(struct page *page)
diff -Nru a/fs/sysv/namei.c b/fs/sysv/namei.c
--- a/fs/sysv/namei.c	Tue Apr 30 17:10:25 2002
+++ b/fs/sysv/namei.c	Tue Apr 30 17:10:25 2002
@@ -12,10 +12,9 @@
  *  Copyright (C) 1997, 1998  Krzysztof G. Baranowski
  */
 
-#include <linux/fs.h>
-#include <linux/sysv_fs.h>
 #include <linux/pagemap.h>
 #include <linux/smp_lock.h>
+#include "sysv.h"
 
 static inline void inc_count(struct inode *inode)
 {
@@ -138,7 +137,7 @@
 {
 	struct inode *inode = old_dentry->d_inode;
 
-	if (inode->i_nlink >= inode->i_sb->sv_link_max)
+	if (inode->i_nlink >= SYSV_SB(inode->i_sb)->s_link_max)
 		return -EMLINK;
 
 	inode->i_ctime = CURRENT_TIME;
@@ -153,7 +152,7 @@
 	struct inode * inode;
 	int err = -EMLINK;
 
-	if (dir->i_nlink >= dir->i_sb->sv_link_max) 
+	if (dir->i_nlink >= SYSV_SB(dir->i_sb)->s_link_max) 
 		goto out;
 	inc_count(dir);
 
@@ -271,7 +270,7 @@
 	} else {
 		if (dir_de) {
 			err = -EMLINK;
-			if (new_dir->i_nlink >= new_dir->i_sb->sv_link_max)
+			if (new_dir->i_nlink >= SYSV_SB(new_dir->i_sb)->s_link_max)
 				goto out_dir;
 		}
 		inc_count(old_inode);
diff -Nru a/fs/sysv/super.c b/fs/sysv/super.c
--- a/fs/sysv/super.c	Tue Apr 30 17:10:23 2002
+++ b/fs/sysv/super.c	Tue Apr 30 17:10:23 2002
@@ -21,10 +21,9 @@
  */
 
 #include <linux/module.h>
-
-#include <linux/fs.h>
-#include <linux/sysv_fs.h>
 #include <linux/init.h>
+#include <linux/slab.h>
+#include "sysv.h"
 
 /*
  * The following functions try to recognize specific filesystems.
@@ -44,10 +43,10 @@
 	JAN_1_1980 = (10*365 + 2) * 24 * 60 * 60
 };
 
-static void detected_xenix(struct super_block *sb)
+static void detected_xenix(struct sysv_sb_info *sbi)
 {
-	struct buffer_head *bh1 = sb->sv_bh1;
-	struct buffer_head *bh2 = sb->sv_bh2;
+	struct buffer_head *bh1 = sbi->s_bh1;
+	struct buffer_head *bh2 = sbi->s_bh2;
 	struct xenix_super_block * sbd1;
 	struct xenix_super_block * sbd2;
 
@@ -59,152 +58,153 @@
 		sbd2 = (struct xenix_super_block *) (bh2->b_data - 512);
 	}
 
-	sb->sv_link_max = XENIX_LINK_MAX;
-	sb->sv_fic_size = XENIX_NICINOD;
-	sb->sv_flc_size = XENIX_NICFREE;
-	sb->sv_sbd1 = (char *) sbd1;
-	sb->sv_sbd2 = (char *) sbd2;
-	sb->sv_sb_fic_count = &sbd1->s_ninode;
-	sb->sv_sb_fic_inodes = &sbd1->s_inode[0];
-	sb->sv_sb_total_free_inodes = &sbd2->s_tinode;
-	sb->sv_bcache_count = &sbd1->s_nfree;
-	sb->sv_bcache = &sbd1->s_free[0];
-	sb->sv_free_blocks = &sbd2->s_tfree;
-	sb->sv_sb_time = &sbd2->s_time;
-	sb->sv_firstdatazone = fs16_to_cpu(sb, sbd1->s_isize);
-	sb->sv_nzones = fs32_to_cpu(sb, sbd1->s_fsize);
+	sbi->s_link_max = XENIX_LINK_MAX;
+	sbi->s_fic_size = XENIX_NICINOD;
+	sbi->s_flc_size = XENIX_NICFREE;
+	sbi->s_sbd1 = (char *)sbd1;
+	sbi->s_sbd2 = (char *)sbd2;
+	sbi->s_sb_fic_count = &sbd1->s_ninode;
+	sbi->s_sb_fic_inodes = &sbd1->s_inode[0];
+	sbi->s_sb_total_free_inodes = &sbd2->s_tinode;
+	sbi->s_bcache_count = &sbd1->s_nfree;
+	sbi->s_bcache = &sbd1->s_free[0];
+	sbi->s_free_blocks = &sbd2->s_tfree;
+	sbi->s_sb_time = &sbd2->s_time;
+	sbi->s_firstdatazone = fs16_to_cpu(sbi, sbd1->s_isize);
+	sbi->s_nzones = fs32_to_cpu(sbi, sbd1->s_fsize);
 }
 
-static void detected_sysv4(struct super_block *sb)
+static void detected_sysv4(struct sysv_sb_info *sbi)
 {
 	struct sysv4_super_block * sbd;
-	struct buffer_head *bh1 = sb->sv_bh1;
-	struct buffer_head *bh2 = sb->sv_bh2;
+	struct buffer_head *bh1 = sbi->s_bh1;
+	struct buffer_head *bh2 = sbi->s_bh2;
 
 	if (bh1 == bh2)
 		sbd = (struct sysv4_super_block *) (bh1->b_data + BLOCK_SIZE/2);
 	else
 		sbd = (struct sysv4_super_block *) bh2->b_data;
 
-	sb->sv_link_max = SYSV_LINK_MAX;
-	sb->sv_fic_size = SYSV_NICINOD;
-	sb->sv_flc_size = SYSV_NICFREE;
-	sb->sv_sbd1 = (char *) sbd;
-	sb->sv_sbd2 = (char *) sbd;
-	sb->sv_sb_fic_count = &sbd->s_ninode;
-	sb->sv_sb_fic_inodes = &sbd->s_inode[0];
-	sb->sv_sb_total_free_inodes = &sbd->s_tinode;
-	sb->sv_bcache_count = &sbd->s_nfree;
-	sb->sv_bcache = &sbd->s_free[0];
-	sb->sv_free_blocks = &sbd->s_tfree;
-	sb->sv_sb_time = &sbd->s_time;
-	sb->sv_sb_state = &sbd->s_state;
-	sb->sv_firstdatazone = fs16_to_cpu(sb, sbd->s_isize);
-	sb->sv_nzones = fs32_to_cpu(sb, sbd->s_fsize);
-}
-
-static void detected_sysv2(struct super_block *sb)
-{
-	struct sysv2_super_block * sbd;
-	struct buffer_head *bh1 = sb->sv_bh1;
-	struct buffer_head *bh2 = sb->sv_bh2;
+	sbi->s_link_max = SYSV_LINK_MAX;
+	sbi->s_fic_size = SYSV_NICINOD;
+	sbi->s_flc_size = SYSV_NICFREE;
+	sbi->s_sbd1 = (char *)sbd;
+	sbi->s_sbd2 = (char *)sbd;
+	sbi->s_sb_fic_count = &sbd->s_ninode;
+	sbi->s_sb_fic_inodes = &sbd->s_inode[0];
+	sbi->s_sb_total_free_inodes = &sbd->s_tinode;
+	sbi->s_bcache_count = &sbd->s_nfree;
+	sbi->s_bcache = &sbd->s_free[0];
+	sbi->s_free_blocks = &sbd->s_tfree;
+	sbi->s_sb_time = &sbd->s_time;
+	sbi->s_sb_state = &sbd->s_state;
+	sbi->s_firstdatazone = fs16_to_cpu(sbi, sbd->s_isize);
+	sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize);
+}
+
+static void detected_sysv2(struct sysv_sb_info *sbi)
+{
+	struct sysv2_super_block *sbd;
+	struct buffer_head *bh1 = sbi->s_bh1;
+	struct buffer_head *bh2 = sbi->s_bh2;
 
 	if (bh1 == bh2)
 		sbd = (struct sysv2_super_block *) (bh1->b_data + BLOCK_SIZE/2);
 	else
 		sbd = (struct sysv2_super_block *) bh2->b_data;
 
-	sb->sv_link_max = SYSV_LINK_MAX;
-	sb->sv_fic_size = SYSV_NICINOD;
-	sb->sv_flc_size = SYSV_NICFREE;
-	sb->sv_sbd1 = (char *) sbd;
-	sb->sv_sbd2 = (char *) sbd;
-	sb->sv_sb_fic_count = &sbd->s_ninode;
-	sb->sv_sb_fic_inodes = &sbd->s_inode[0];
-	sb->sv_sb_total_free_inodes = &sbd->s_tinode;
-	sb->sv_bcache_count = &sbd->s_nfree;
-	sb->sv_bcache = &sbd->s_free[0];
-	sb->sv_free_blocks = &sbd->s_tfree;
-	sb->sv_sb_time = &sbd->s_time;
-	sb->sv_sb_state = &sbd->s_state;
-	sb->sv_firstdatazone = fs16_to_cpu(sb, sbd->s_isize);
-	sb->sv_nzones = fs32_to_cpu(sb, sbd->s_fsize);
+	sbi->s_link_max = SYSV_LINK_MAX;
+	sbi->s_fic_size = SYSV_NICINOD;
+	sbi->s_flc_size = SYSV_NICFREE;
+	sbi->s_sbd1 = (char *)sbd;
+	sbi->s_sbd2 = (char *)sbd;
+	sbi->s_sb_fic_count = &sbd->s_ninode;
+	sbi->s_sb_fic_inodes = &sbd->s_inode[0];
+	sbi->s_sb_total_free_inodes = &sbd->s_tinode;
+	sbi->s_bcache_count = &sbd->s_nfree;
+	sbi->s_bcache = &sbd->s_free[0];
+	sbi->s_free_blocks = &sbd->s_tfree;
+	sbi->s_sb_time = &sbd->s_time;
+	sbi->s_sb_state = &sbd->s_state;
+	sbi->s_firstdatazone = fs16_to_cpu(sbi, sbd->s_isize);
+	sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize);
 }
 
-static void detected_coherent(struct super_block *sb)
+static void detected_coherent(struct sysv_sb_info *sbi)
 {
 	struct coh_super_block * sbd;
-	struct buffer_head *bh1 = sb->sv_bh1;
+	struct buffer_head *bh1 = sbi->s_bh1;
 
 	sbd = (struct coh_super_block *) bh1->b_data;
 
-	sb->sv_link_max = COH_LINK_MAX;
-	sb->sv_fic_size = COH_NICINOD;
-	sb->sv_flc_size = COH_NICFREE;
-	sb->sv_sbd1 = (char *) sbd;
-	sb->sv_sbd2 = (char *) sbd;
-	sb->sv_sb_fic_count = &sbd->s_ninode;
-	sb->sv_sb_fic_inodes = &sbd->s_inode[0];
-	sb->sv_sb_total_free_inodes = &sbd->s_tinode;
-	sb->sv_bcache_count = &sbd->s_nfree;
-	sb->sv_bcache = &sbd->s_free[0];
-	sb->sv_free_blocks = &sbd->s_tfree;
-	sb->sv_sb_time = &sbd->s_time;
-	sb->sv_firstdatazone = fs16_to_cpu(sb, sbd->s_isize);
-	sb->sv_nzones = fs32_to_cpu(sb, sbd->s_fsize);
+	sbi->s_link_max = COH_LINK_MAX;
+	sbi->s_fic_size = COH_NICINOD;
+	sbi->s_flc_size = COH_NICFREE;
+	sbi->s_sbd1 = (char *)sbd;
+	sbi->s_sbd2 = (char *)sbd;
+	sbi->s_sb_fic_count = &sbd->s_ninode;
+	sbi->s_sb_fic_inodes = &sbd->s_inode[0];
+	sbi->s_sb_total_free_inodes = &sbd->s_tinode;
+	sbi->s_bcache_count = &sbd->s_nfree;
+	sbi->s_bcache = &sbd->s_free[0];
+	sbi->s_free_blocks = &sbd->s_tfree;
+	sbi->s_sb_time = &sbd->s_time;
+	sbi->s_firstdatazone = fs16_to_cpu(sbi, sbd->s_isize);
+	sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize);
 }
 
-static void detected_v7(struct super_block *sb)
+static void detected_v7(struct sysv_sb_info *sbi)
 {
-	struct buffer_head *bh2 = sb->sv_bh2;
+	struct buffer_head *bh2 = sbi->s_bh2;
 	struct v7_super_block *sbd = (struct v7_super_block *)bh2->b_data;
 
-	sb->sv_link_max = V7_LINK_MAX;
-	sb->sv_fic_size = V7_NICINOD;
-	sb->sv_flc_size = V7_NICFREE;
-	sb->sv_sbd1 = (char *)sbd;
-	sb->sv_sbd2 = (char *)sbd;
-	sb->sv_sb_fic_count = &sbd->s_ninode;
-	sb->sv_sb_fic_inodes = &sbd->s_inode[0];
-	sb->sv_sb_total_free_inodes = &sbd->s_tinode;
-	sb->sv_bcache_count = &sbd->s_nfree;
-	sb->sv_bcache = &sbd->s_free[0];
-	sb->sv_free_blocks = &sbd->s_tfree;
-	sb->sv_sb_time = &sbd->s_time;
-	sb->sv_firstdatazone = fs16_to_cpu(sb, sbd->s_isize);
-	sb->sv_nzones = fs32_to_cpu(sb, sbd->s_fsize);
+	sbi->s_link_max = V7_LINK_MAX;
+	sbi->s_fic_size = V7_NICINOD;
+	sbi->s_flc_size = V7_NICFREE;
+	sbi->s_sbd1 = (char *)sbd;
+	sbi->s_sbd2 = (char *)sbd;
+	sbi->s_sb_fic_count = &sbd->s_ninode;
+	sbi->s_sb_fic_inodes = &sbd->s_inode[0];
+	sbi->s_sb_total_free_inodes = &sbd->s_tinode;
+	sbi->s_bcache_count = &sbd->s_nfree;
+	sbi->s_bcache = &sbd->s_free[0];
+	sbi->s_free_blocks = &sbd->s_tfree;
+	sbi->s_sb_time = &sbd->s_time;
+	sbi->s_firstdatazone = fs16_to_cpu(sbi, sbd->s_isize);
+	sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize);
 }
 
-static int detect_xenix (struct super_block *sb, struct buffer_head *bh)
+static int detect_xenix(struct sysv_sb_info *sbi, struct buffer_head *bh)
 {
-	struct xenix_super_block * sbd = (struct xenix_super_block *)bh->b_data;
+	struct xenix_super_block *sbd = (struct xenix_super_block *)bh->b_data;
 	if (sbd->s_magic == cpu_to_le32(0x2b5544))
-		sb->sv_bytesex = BYTESEX_LE;
+		sbi->s_bytesex = BYTESEX_LE;
 	else if (sbd->s_magic == cpu_to_be32(0x2b5544))
-		sb->sv_bytesex = BYTESEX_BE;
+		sbi->s_bytesex = BYTESEX_BE;
 	else
 		return 0;
 	if (sbd->s_type > 2 || sbd->s_type < 1)
 		return 0;
-	sb->sv_type = FSTYPE_XENIX;
+	sbi->s_type = FSTYPE_XENIX;
 	return sbd->s_type;
 }
 
-static int detect_sysv (struct super_block *sb, struct buffer_head *bh)
+static int detect_sysv(struct sysv_sb_info *sbi, struct buffer_head *bh)
 {
+	struct super_block *sb = sbi->s_sb;
 	/* All relevant fields are at the same offsets in R2 and R4 */
 	struct sysv4_super_block * sbd;
 
 	sbd = (struct sysv4_super_block *) (bh->b_data + BLOCK_SIZE/2);
 	if (sbd->s_magic == cpu_to_le32(0xfd187e20))
-		sb->sv_bytesex = BYTESEX_LE;
+		sbi->s_bytesex = BYTESEX_LE;
 	else if (sbd->s_magic == cpu_to_be32(0xfd187e20))
-		sb->sv_bytesex = BYTESEX_BE;
+		sbi->s_bytesex = BYTESEX_BE;
 	else
 		return 0;
  
- 	if (fs16_to_cpu(sb, sbd->s_nfree) == 0xffff) {
- 		sb->sv_type = FSTYPE_AFS;
+ 	if (fs16_to_cpu(sbi, sbd->s_nfree) == 0xffff) {
+ 		sbi->s_type = FSTYPE_AFS;
  		if (!(sb->s_flags & MS_RDONLY)) {
  			printk("SysV FS: SCO EAFS on %s detected, " 
  				"forcing read-only mode.\n", 
@@ -214,11 +214,11 @@
  		return sbd->s_type;
  	}
  
-	if (fs32_to_cpu(sb, sbd->s_time) < JAN_1_1980) {
+	if (fs32_to_cpu(sbi, sbd->s_time) < JAN_1_1980) {
 		/* this is likely to happen on SystemV2 FS */
 		if (sbd->s_type > 3 || sbd->s_type < 1)
 			return 0;
-		sb->sv_type = FSTYPE_SYSV2;
+		sbi->s_type = FSTYPE_SYSV2;
 		return sbd->s_type;
 	}
 	if ((sbd->s_type > 3 || sbd->s_type < 1) &&
@@ -236,11 +236,11 @@
 		sb->s_flags |= MS_RDONLY;
 	}
 
-	sb->sv_type = FSTYPE_SYSV4;
+	sbi->s_type = FSTYPE_SYSV4;
 	return sbd->s_type >= 0x10 ? (sbd->s_type >> 4) : sbd->s_type;
 }
 
-static int detect_coherent (struct super_block *sb, struct buffer_head *bh)
+static int detect_coherent(struct sysv_sb_info *sbi, struct buffer_head *bh)
 {
 	struct coh_super_block * sbd;
 
@@ -248,21 +248,21 @@
 	if ((memcmp(sbd->s_fname,"noname",6) && memcmp(sbd->s_fname,"xxxxx ",6))
 	    || (memcmp(sbd->s_fpack,"nopack",6) && memcmp(sbd->s_fpack,"xxxxx\n",6)))
 		return 0;
-	sb->sv_bytesex = BYTESEX_PDP;
-	sb->sv_type = FSTYPE_COH;
+	sbi->s_bytesex = BYTESEX_PDP;
+	sbi->s_type = FSTYPE_COH;
 	return 1;
 }
 
-static int detect_sysv_odd(struct super_block *sb, struct buffer_head *bh)
+static int detect_sysv_odd(struct sysv_sb_info *sbi, struct buffer_head *bh)
 {
-	int size = detect_sysv(sb, bh);
+	int size = detect_sysv(sbi, bh);
 
 	return size>2 ? 0 : size;
 }
 
 static struct {
 	int block;
-	int (*test)(struct super_block *, struct buffer_head *);
+	int (*test)(struct sysv_sb_info *, struct buffer_head *);
 } flavours[] = {
 	{1, detect_xenix},
 	{0, detect_sysv},
@@ -281,7 +281,7 @@
 	[FSTYPE_AFS]	"AFS",
 };
 
-static void (*flavour_setup[])(struct super_block *) = {
+static void (*flavour_setup[])(struct sysv_sb_info *) = {
 	[FSTYPE_XENIX]	detected_xenix,
 	[FSTYPE_SYSV4]	detected_sysv4,
 	[FSTYPE_SYSV2]	detected_sysv2,
@@ -292,34 +292,35 @@
 
 static int complete_read_super(struct super_block *sb, int silent, int size)
 {
+	struct sysv_sb_info *sbi = SYSV_SB(sb);
 	struct inode *root_inode;
-	char *found = flavour_names[sb->sv_type];
+	char *found = flavour_names[sbi->s_type];
 	u_char n_bits = size+8;
 	int bsize = 1 << n_bits;
 	int bsize_4 = bsize >> 2;
 
-	sb->sv_firstinodezone = 2;
+	sbi->s_firstinodezone = 2;
 
-	flavour_setup[sb->sv_type](sb);
+	flavour_setup[sbi->s_type](sbi);
 	
-	sb->sv_truncate = 1;
-	sb->sv_ndatazones = sb->sv_nzones - sb->sv_firstdatazone;
-	sb->sv_inodes_per_block = bsize >> 6;
-	sb->sv_inodes_per_block_1 = (bsize >> 6)-1;
-	sb->sv_inodes_per_block_bits = n_bits-6;
-	sb->sv_ind_per_block = bsize_4;
-	sb->sv_ind_per_block_2 = bsize_4*bsize_4;
-	sb->sv_toobig_block = 10 + bsize_4 * (1 + bsize_4 * (1 + bsize_4));
-	sb->sv_ind_per_block_bits = n_bits-2;
+	sbi->s_truncate = 1;
+	sbi->s_ndatazones = sbi->s_nzones - sbi->s_firstdatazone;
+	sbi->s_inodes_per_block = bsize >> 6;
+	sbi->s_inodes_per_block_1 = (bsize >> 6)-1;
+	sbi->s_inodes_per_block_bits = n_bits-6;
+	sbi->s_ind_per_block = bsize_4;
+	sbi->s_ind_per_block_2 = bsize_4*bsize_4;
+	sbi->s_toobig_block = 10 + bsize_4 * (1 + bsize_4 * (1 + bsize_4));
+	sbi->s_ind_per_block_bits = n_bits-2;
 
-	sb->sv_ninodes = (sb->sv_firstdatazone - sb->sv_firstinodezone)
-		<< sb->sv_inodes_per_block_bits;
+	sbi->s_ninodes = (sbi->s_firstdatazone - sbi->s_firstinodezone)
+		<< sbi->s_inodes_per_block_bits;
 
 	if (!silent)
 		printk("VFS: Found a %s FS (block size = %ld) on device %s\n",
 		       found, sb->s_blocksize, sb->s_id);
 
-	sb->s_magic = SYSV_MAGIC_BASE + sb->sv_type;
+	sb->s_magic = SYSV_MAGIC_BASE + sbi->s_type;
 	/* set up enough so that it can read an inode */
 	sb->s_op = &sysv_sops;
 	root_inode = iget(sb,SYSV_ROOT_INO);
@@ -333,7 +334,7 @@
 		printk("SysV FS: get root dentry failed\n");
 		return 0;
 	}
-	if (sb->sv_truncate)
+	if (sbi->s_truncate)
 		sb->s_root->d_op = &sysv_dentry_operations;
 	sb->s_flags |= MS_RDONLY;
 	sb->s_dirt = 1;
@@ -342,30 +343,39 @@
 
 static int sysv_fill_super(struct super_block *sb, void *data, int silent)
 {
-	struct buffer_head *bh1;
-	struct buffer_head *bh = NULL;
+	struct buffer_head *bh1, *bh = NULL;
+	struct sysv_sb_info *sbi;
 	unsigned long blocknr;
-	int size = 0;
-	int i;
+	int size = 0, i;
 	
 	if (1024 != sizeof (struct xenix_super_block))
-		panic("Xenix FS: bad super-block size");
-	if ((512 != sizeof (struct sysv4_super_block))
-            || (512 != sizeof (struct sysv2_super_block)))
-		panic("SystemV FS: bad super-block size");
+		panic("Xenix FS: bad superblock size");
+	if (512 != sizeof (struct sysv4_super_block))
+		panic("SystemV FS: bad superblock size");
+	if (512 != sizeof (struct sysv2_super_block))
+		panic("SystemV FS: bad superblock size");
 	if (500 != sizeof (struct coh_super_block))
-		panic("Coherent FS: bad super-block size");
+		panic("Coherent FS: bad superblock size");
 	if (64 != sizeof (struct sysv_inode))
-		panic("sysv fs: bad i-node size");
+		panic("sysv fs: bad inode size");
+
+	sbi = kmalloc(sizeof(struct sysv_sb_info), GFP_KERNEL);
+	if (!sbi)
+		return -ENOMEM;
+	memset(sbi, 0, sizeof(struct sysv_sb_info));
+
+	sbi->s_sb = sb;
+	sbi->s_block_base = 0;
+	sb->u.generic_sbp = sbi;
+	
 	sb_set_blocksize(sb, BLOCK_SIZE);
-	sb->sv_block_base = 0;
 
 	for (i = 0; i < sizeof(flavours)/sizeof(flavours[0]) && !size; i++) {
 		brelse(bh);
 		bh = sb_bread(sb, flavours[i].block);
 		if (!bh)
 			continue;
-		size = flavours[i].test(sb, bh);
+		size = flavours[i].test(SYSV_SB(sb), bh);
 	}
 
 	if (!size)
@@ -393,8 +403,8 @@
 	}
 
 	if (bh && bh1) {
-		sb->sv_bh1 = bh1;
-		sb->sv_bh2 = bh;
+		sbi->s_bh1 = bh1;
+		sbi->s_bh2 = bh;
 		if (complete_read_super(sb, silent, size))
 			return 0;
 	}
@@ -404,6 +414,7 @@
 	sb_set_blocksize(sb, BLOCK_SIZE);
 	printk("oldfs: cannot read superblock\n");
 failed:
+	kfree(sbi);
 	return -EINVAL;
 
 Eunknown:
@@ -422,6 +433,7 @@
 
 static int v7_fill_super(struct super_block *sb, void *data, int silent)
 {
+	struct sysv_sb_info *sbi;
 	struct buffer_head *bh, *bh2 = NULL;
 	struct v7_super_block *v7sb;
 	struct sysv_inode *v7i;
@@ -431,9 +443,17 @@
 	if (64 != sizeof (struct sysv_inode))
 		panic("sysv fs: bad i-node size");
 
-	sb->sv_type = FSTYPE_V7;
-	sb->sv_bytesex = BYTESEX_PDP;
-
+	sbi = kmalloc(sizeof(struct sysv_sb_info), GFP_KERNEL);
+	if (!sbi)
+		return -ENOMEM;
+	memset(sbi, 0, sizeof(struct sysv_sb_info));
+
+	sbi->s_sb = sb;
+	sbi->s_block_base = 0;
+	sbi->s_type = FSTYPE_V7;
+	sbi->s_bytesex = BYTESEX_PDP;
+	sb->u.generic_sbp = sbi;
+	
 	sb_set_blocksize(sb, 512);
 
 	if ((bh = sb_bread(sb, 1)) == NULL) {
@@ -445,9 +465,9 @@
 
 	/* plausibility check on superblock */
 	v7sb = (struct v7_super_block *) bh->b_data;
-	if (fs16_to_cpu(sb,v7sb->s_nfree) > V7_NICFREE ||
-	    fs16_to_cpu(sb,v7sb->s_ninode) > V7_NICINOD ||
-	    fs32_to_cpu(sb,v7sb->s_time) == 0)
+	if (fs16_to_cpu(sbi, v7sb->s_nfree) > V7_NICFREE ||
+	    fs16_to_cpu(sbi, v7sb->s_ninode) > V7_NICINOD ||
+	    fs32_to_cpu(sbi, v7sb->s_time) == 0)
 		goto failed;
 
 	/* plausibility check on root inode: it is a directory,
@@ -455,20 +475,21 @@
 	if ((bh2 = sb_bread(sb, 2)) == NULL)
 		goto failed;
 	v7i = (struct sysv_inode *)(bh2->b_data + 64);
-	if ((fs16_to_cpu(sb,v7i->i_mode) & ~0777) != S_IFDIR ||
-	    (fs32_to_cpu(sb,v7i->i_size) == 0) ||
-	    (fs32_to_cpu(sb,v7i->i_size) & 017) != 0)
+	if ((fs16_to_cpu(sbi, v7i->i_mode) & ~0777) != S_IFDIR ||
+	    (fs32_to_cpu(sbi, v7i->i_size) == 0) ||
+	    (fs32_to_cpu(sbi, v7i->i_size) & 017) != 0)
 		goto failed;
 	brelse(bh2);
 
-	sb->sv_bh1 = bh;
-	sb->sv_bh2 = bh;
+	sbi->s_bh1 = bh;
+	sbi->s_bh2 = bh;
 	if (complete_read_super(sb, silent, 1))
 		return 0;
 
 failed:
 	brelse(bh2);
 	brelse(bh);
+	kfree(sbi);
 	return -EINVAL;
 }
 
diff -Nru a/fs/sysv/symlink.c b/fs/sysv/symlink.c
--- a/fs/sysv/symlink.c	Tue Apr 30 17:10:25 2002
+++ b/fs/sysv/symlink.c	Tue Apr 30 17:10:25 2002
@@ -5,8 +5,7 @@
  *  Aug 2001, Christoph Hellwig (hch@infradead.org)
  */
 
-#include <linux/fs.h>
-#include <linux/sysv_fs.h>
+#include "sysv.h"
 
 static int sysv_readlink(struct dentry *dentry, char *buffer, int buflen)
 {
diff -Nru a/fs/sysv/sysv.h b/fs/sysv/sysv.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/sysv/sysv.h	Tue Apr 30 17:10:25 2002
@@ -0,0 +1,236 @@
+#ifndef _SYSV_H
+#define _SYSV_H
+
+#include <linux/fs.h>
+#include <linux/sysv_fs.h>
+
+/*
+ * SystemV/V7/Coherent super-block data in memory
+ *
+ * The SystemV/V7/Coherent superblock contains dynamic data (it gets modified
+ * while the system is running). This is in contrast to the Minix and Berkeley
+ * filesystems (where the superblock is never modified). This affects the
+ * sync() operation: we must keep the superblock in a disk buffer and use this
+ * one as our "working copy".
+ */
+
+struct sysv_sb_info {
+	struct super_block *s_sb;	/* VFS superblock */
+	int	       s_type;		/* file system type: FSTYPE_{XENIX|SYSV|COH} */
+	char	       s_bytesex;	/* bytesex (le/be/pdp) */
+	char	       s_truncate;	/* if 1: names > SYSV_NAMELEN chars are truncated */
+					/* if 0: they are disallowed (ENAMETOOLONG) */
+	nlink_t        s_link_max;	/* max number of hard links to a file */
+	unsigned int   s_inodes_per_block;	/* number of inodes per block */
+	unsigned int   s_inodes_per_block_1;	/* inodes_per_block - 1 */
+	unsigned int   s_inodes_per_block_bits;	/* log2(inodes_per_block) */
+	unsigned int   s_ind_per_block;		/* number of indirections per block */
+	unsigned int   s_ind_per_block_bits;	/* log2(ind_per_block) */
+	unsigned int   s_ind_per_block_2;	/* ind_per_block ^ 2 */
+	unsigned int   s_toobig_block;		/* 10 + ipb + ipb^2 + ipb^3 */
+	unsigned int   s_block_base;	/* physical block number of block 0 */
+	unsigned short s_fic_size;	/* free inode cache size, NICINOD */
+	unsigned short s_flc_size;	/* free block list chunk size, NICFREE */
+	/* The superblock is kept in one or two disk buffers: */
+	struct buffer_head *s_bh1;
+	struct buffer_head *s_bh2;
+	/* These are pointers into the disk buffer, to compensate for
+	   different superblock layout. */
+	char *         s_sbd1;		/* entire superblock data, for part 1 */
+	char *         s_sbd2;		/* entire superblock data, for part 2 */
+	u16            *s_sb_fic_count;	/* pointer to s_sbd->s_ninode */
+        u16            *s_sb_fic_inodes; /* pointer to s_sbd->s_inode */
+	u16            *s_sb_total_free_inodes; /* pointer to s_sbd->s_tinode */
+	u16            *s_bcache_count;	/* pointer to s_sbd->s_nfree */
+	u32	       *s_bcache;	/* pointer to s_sbd->s_free */
+	u32            *s_free_blocks;	/* pointer to s_sbd->s_tfree */
+	u32            *s_sb_time;	/* pointer to s_sbd->s_time */
+	u32            *s_sb_state;	/* pointer to s_sbd->s_state, only FSTYPE_SYSV */
+	/* We keep those superblock entities that don't change here;
+	   this saves us an indirection and perhaps a conversion. */
+	u32            s_firstinodezone; /* index of first inode zone */
+	u32            s_firstdatazone;	/* same as s_sbd->s_isize */
+	u32            s_ninodes;	/* total number of inodes */
+	u32            s_ndatazones;	/* total number of data zones */
+	u32            s_nzones;	/* same as s_sbd->s_fsize */
+	u16	       s_namelen;       /* max length of dir entry */
+};
+
+/*
+ * SystemV/V7/Coherent FS inode data in memory
+ */
+struct sysv_inode_info {
+	u32		i_data[13];
+	u32		i_dir_start_lookup;
+	struct inode	vfs_inode;
+};
+
+
+static inline struct sysv_inode_info *SYSV_I(struct inode *inode)
+{
+	return list_entry(inode, struct sysv_inode_info, vfs_inode);
+}
+
+static inline struct sysv_sb_info *SYSV_SB(struct super_block *sb)
+{
+	return sb->u.generic_sbp;
+}
+
+
+/* identify the FS in memory */
+enum {
+	FSTYPE_NONE = 0,
+	FSTYPE_XENIX,
+	FSTYPE_SYSV4,
+	FSTYPE_SYSV2,
+	FSTYPE_COH,
+	FSTYPE_V7,
+	FSTYPE_AFS,
+	FSTYPE_END,
+};
+
+#define SYSV_MAGIC_BASE		0x012FF7B3
+
+#define XENIX_SUPER_MAGIC	(SYSV_MAGIC_BASE+FSTYPE_XENIX)
+#define SYSV4_SUPER_MAGIC	(SYSV_MAGIC_BASE+FSTYPE_SYSV4)
+#define SYSV2_SUPER_MAGIC	(SYSV_MAGIC_BASE+FSTYPE_SYSV2)
+#define COH_SUPER_MAGIC		(SYSV_MAGIC_BASE+FSTYPE_COH)
+
+
+/* Admissible values for i_nlink: 0.._LINK_MAX */
+enum {
+	XENIX_LINK_MAX	=	126,	/* ?? */
+	SYSV_LINK_MAX	=	126,	/* 127? 251? */
+	V7_LINK_MAX     =	126,	/* ?? */
+	COH_LINK_MAX	=	10000,
+};
+
+
+static inline void dirty_sb(struct super_block *sb)
+{
+	struct sysv_sb_info *sbi = SYSV_SB(sb);
+
+	mark_buffer_dirty(sbi->s_bh1);
+	if (sbi->s_bh1 != sbi->s_bh2)
+		mark_buffer_dirty(sbi->s_bh2);
+	sb->s_dirt = 1;
+}
+
+
+/* ialloc.c */
+extern struct sysv_inode *sysv_raw_inode(struct super_block *, unsigned,
+			struct buffer_head **);
+extern struct inode * sysv_new_inode(const struct inode *, mode_t);
+extern void sysv_free_inode(struct inode *);
+extern unsigned long sysv_count_free_inodes(struct super_block *);
+
+/* balloc.c */
+extern u32 sysv_new_block(struct super_block *);
+extern void sysv_free_block(struct super_block *, u32);
+extern unsigned long sysv_count_free_blocks(struct super_block *);
+
+/* itree.c */
+extern void sysv_truncate(struct inode *);
+
+/* inode.c */
+extern void sysv_write_inode(struct inode *, int);
+extern int sysv_sync_inode(struct inode *);
+extern int sysv_sync_file(struct file *, struct dentry *, int);
+extern void sysv_set_inode(struct inode *, dev_t);
+
+/* dir.c */
+extern struct sysv_dir_entry *sysv_find_entry(struct dentry *, struct page **);
+extern int sysv_add_link(struct dentry *, struct inode *);
+extern int sysv_delete_entry(struct sysv_dir_entry *, struct page *);
+extern int sysv_make_empty(struct inode *, struct inode *);
+extern int sysv_empty_dir(struct inode *);
+extern void sysv_set_link(struct sysv_dir_entry *, struct page *,
+			struct inode *);
+extern struct sysv_dir_entry *sysv_dotdot(struct inode *, struct page **);
+extern ino_t sysv_inode_by_name(struct dentry *);
+
+
+extern struct inode_operations sysv_file_inode_operations;
+extern struct inode_operations sysv_dir_inode_operations;
+extern struct inode_operations sysv_fast_symlink_inode_operations;
+extern struct file_operations sysv_file_operations;
+extern struct file_operations sysv_dir_operations;
+extern struct address_space_operations sysv_aops;
+extern struct super_operations sysv_sops;
+extern struct dentry_operations sysv_dentry_operations;
+
+
+enum {
+	BYTESEX_LE,
+	BYTESEX_PDP,
+	BYTESEX_BE,
+};
+
+static inline u32 PDP_swab(u32 x)
+{
+#ifdef __LITTLE_ENDIAN
+	return ((x & 0xffff) << 16) | ((x & 0xffff0000) >> 16);
+#else
+#ifdef __BIG_ENDIAN
+	return ((x & 0xff00ff) << 8) | ((x & 0xff00ff00) >> 8);
+#else
+#error BYTESEX
+#endif
+#endif
+}
+
+static inline u32 fs32_to_cpu(struct sysv_sb_info *sbi, u32 n)
+{
+	if (sbi->s_bytesex == BYTESEX_PDP)
+		return PDP_swab(n);
+	else if (sbi->s_bytesex == BYTESEX_LE)
+		return le32_to_cpu(n);
+	else
+		return be32_to_cpu(n);
+}
+
+static inline u32 cpu_to_fs32(struct sysv_sb_info *sbi, u32 n)
+{
+	if (sbi->s_bytesex == BYTESEX_PDP)
+		return PDP_swab(n);
+	else if (sbi->s_bytesex == BYTESEX_LE)
+		return cpu_to_le32(n);
+	else
+		return cpu_to_be32(n);
+}
+
+static inline u32 fs32_add(struct sysv_sb_info *sbi, u32 *n, int d)
+{
+	if (sbi->s_bytesex == BYTESEX_PDP)
+		return *n = PDP_swab(PDP_swab(*n)+d);
+	else if (sbi->s_bytesex == BYTESEX_LE)
+		return *n = cpu_to_le32(le32_to_cpu(*n)+d);
+	else
+		return *n = cpu_to_be32(be32_to_cpu(*n)+d);
+}
+
+static inline u16 fs16_to_cpu(struct sysv_sb_info *sbi, u16 n)
+{
+	if (sbi->s_bytesex != BYTESEX_BE)
+		return le16_to_cpu(n);
+	else
+		return be16_to_cpu(n);
+}
+
+static inline u16 cpu_to_fs16(struct sysv_sb_info *sbi, u16 n)
+{
+	if (sbi->s_bytesex != BYTESEX_BE)
+		return cpu_to_le16(n);
+	else
+		return cpu_to_be16(n);
+}
+
+static inline u16 fs16_add(struct sysv_sb_info *sbi, u16 *n, int d)
+{
+	if (sbi->s_bytesex != BYTESEX_BE)
+		return *n = cpu_to_le16(le16_to_cpu(*n)+d);
+	else
+		return *n = cpu_to_be16(be16_to_cpu(*n)+d);
+}
+
+#endif /* _SYSV_H */
diff -Nru a/fs/udf/dir.c b/fs/udf/dir.c
--- a/fs/udf/dir.c	Tue Apr 30 17:10:25 2002
+++ b/fs/udf/dir.c	Tue Apr 30 17:10:25 2002
@@ -35,6 +35,7 @@
 #include <linux/errno.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 
 #include "udf_i.h"
 #include "udf_sb.h"
@@ -83,15 +84,20 @@
 	struct inode *dir = filp->f_dentry->d_inode;
 	int result;
 
+	lock_kernel();
+
 	if ( filp->f_pos == 0 ) 
 	{
-		if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino, DT_DIR) < 0)
+		if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino, DT_DIR) < 0) {
+			unlock_kernel();
 			return 0;
+		}
 		filp->f_pos ++;
 	}
  
 	result = do_udf_readdir(dir, filp, filldir, dirent);
 	UPDATE_ATIME(dir);
+	unlock_kernel();
  	return result;
 }
 
diff -Nru a/fs/udf/file.c b/fs/udf/file.c
--- a/fs/udf/file.c	Tue Apr 30 17:10:23 2002
+++ b/fs/udf/file.c	Tue Apr 30 17:10:23 2002
@@ -71,7 +71,7 @@
 	SetPageUptodate(page);
 out:
 	kunmap(page);
-	UnlockPage(page);
+	unlock_page(page);
 	return err;
 }
 
@@ -102,7 +102,7 @@
 	SetPageUptodate(page);
 out:
 	kunmap(page);
-	UnlockPage(page);
+	unlock_page(page);
 	return err;
 }
 
diff -Nru a/fs/udf/fsync.c b/fs/udf/fsync.c
--- a/fs/udf/fsync.c	Tue Apr 30 17:10:24 2002
+++ b/fs/udf/fsync.c	Tue Apr 30 17:10:24 2002
@@ -45,7 +45,6 @@
 	int err;
 
 	err = fsync_inode_buffers(inode);
-	err |= fsync_inode_data_buffers(inode);
 	if (!(inode->i_state & I_DIRTY))
 		return err;
 	if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
diff -Nru a/fs/udf/inode.c b/fs/udf/inode.c
--- a/fs/udf/inode.c	Tue Apr 30 17:10:25 2002
+++ b/fs/udf/inode.c	Tue Apr 30 17:10:25 2002
@@ -186,7 +186,7 @@
 	page = grab_cache_page(inode->i_mapping, 0);
 	if (!PageLocked(page))
 		PAGE_BUG(page);
-	if (!Page_Uptodate(page))
+	if (!PageUptodate(page))
 	{
 		kaddr = kmap(page);
 		memset(kaddr + UDF_I_LENALLOC(inode), 0x00,
@@ -254,7 +254,7 @@
 		return NULL;
 	lock_buffer(dbh);
 	memset(dbh->b_data, 0x00, inode->i_sb->s_blocksize);
-	mark_buffer_uptodate(dbh, 1);
+	set_buffer_uptodate(dbh);
 	unlock_buffer(dbh);
 	mark_buffer_dirty_inode(dbh, inode);
 
@@ -348,7 +348,7 @@
 		BUG();
 
 	if (new)
-		bh_result->b_state |= (1UL << BH_New);
+		set_buffer_new(bh_result);
 	map_bh(bh_result, inode->i_sb, phys);
 abort:
 	unlock_kernel();
@@ -375,7 +375,7 @@
 		{
 			lock_buffer(bh);
 			memset(bh->b_data, 0x00, inode->i_sb->s_blocksize);
-			mark_buffer_uptodate(bh, 1);
+			set_buffer_uptodate(bh);
 			unlock_buffer(bh);
 			mark_buffer_dirty_inode(bh, inode);
 		}
@@ -1656,7 +1656,7 @@
 		}
 		lock_buffer(nbh);
 		memset(nbh->b_data, 0x00, inode->i_sb->s_blocksize);
-		mark_buffer_uptodate(nbh, 1);
+		set_buffer_uptodate(nbh);
 		unlock_buffer(nbh);
 		mark_buffer_dirty_inode(nbh, inode);
 
diff -Nru a/fs/udf/namei.c b/fs/udf/namei.c
--- a/fs/udf/namei.c	Tue Apr 30 17:10:25 2002
+++ b/fs/udf/namei.c	Tue Apr 30 17:10:25 2002
@@ -984,7 +984,7 @@
 		bh = udf_tread(inode->i_sb, block);
 		lock_buffer(bh);
 		memset(bh->b_data, 0x00, inode->i_sb->s_blocksize);
-		mark_buffer_uptodate(bh, 1);
+		set_buffer_uptodate(bh);
 		unlock_buffer(bh);
 		mark_buffer_dirty_inode(bh, inode);
 	}
diff -Nru a/fs/udf/symlink.c b/fs/udf/symlink.c
--- a/fs/udf/symlink.c	Tue Apr 30 17:10:25 2002
+++ b/fs/udf/symlink.c	Tue Apr 30 17:10:25 2002
@@ -111,13 +111,13 @@
 	unlock_kernel();
 	SetPageUptodate(page);
 	kunmap(page);
-	UnlockPage(page);
+	unlock_page(page);
 	return 0;
 out:
 	unlock_kernel();
 	SetPageError(page);
 	kunmap(page);
-	UnlockPage(page);
+	unlock_page(page);
 	return err;
 }
 
diff -Nru a/fs/ufs/balloc.c b/fs/ufs/balloc.c
--- a/fs/ufs/balloc.c	Tue Apr 30 17:10:23 2002
+++ b/fs/ufs/balloc.c	Tue Apr 30 17:10:23 2002
@@ -225,7 +225,7 @@
 	for (i = oldcount; i < newcount; i++) { \
 		bh = sb_getblk(sb, result + i); \
 		memset (bh->b_data, 0, sb->s_blocksize); \
-		mark_buffer_uptodate(bh, 1); \
+		set_buffer_uptodate(bh); \
 		mark_buffer_dirty (bh); \
 		if (IS_SYNC(inode)) { \
 			ll_rw_block (WRITE, 1, &bh); \
@@ -360,7 +360,7 @@
 			bh = sb_bread(sb, tmp + i);
 			if(bh)
 			{
-				mark_buffer_clean (bh);
+				clear_buffer_dirty(bh);
 				bh->b_blocknr = result + i;
 				mark_buffer_dirty (bh);
 				if (IS_SYNC(inode)) {
diff -Nru a/fs/ufs/dir.c b/fs/ufs/dir.c
--- a/fs/ufs/dir.c	Tue Apr 30 17:10:25 2002
+++ b/fs/ufs/dir.c	Tue Apr 30 17:10:25 2002
@@ -17,6 +17,7 @@
 #include <linux/locks.h>
 #include <linux/fs.h>
 #include <linux/ufs_fs.h>
+#include <linux/smp_lock.h>
 
 #include "swab.h"
 #include "util.h"
@@ -62,6 +63,8 @@
 	int de_reclen;
 	unsigned flags;
 
+	lock_kernel();
+
 	sb = inode->i_sb;
 	flags = sb->u.ufs_sb.s_flags;
 
@@ -117,6 +120,7 @@
 				              (sb->s_blocksize - 1)) +
 				               sb->s_blocksize;
 				brelse(bh);
+				unlock_kernel();
 				return stored;
 			}
 			if (!ufs_check_dir_entry ("ufs_readdir", inode, de,
@@ -127,6 +131,7 @@
 				              (sb->s_blocksize - 1)) +
 					       1;
 				brelse (bh);
+				unlock_kernel();
 				return stored;
 			}
 			offset += fs16_to_cpu(sb, de->d_reclen);
@@ -161,6 +166,7 @@
 		brelse (bh);
 	}
 	UPDATE_ATIME(inode);
+	unlock_kernel();
 	return 0;
 }
 
diff -Nru a/fs/ufs/inode.c b/fs/ufs/inode.c
--- a/fs/ufs/inode.c	Tue Apr 30 17:10:25 2002
+++ b/fs/ufs/inode.c	Tue Apr 30 17:10:25 2002
@@ -389,7 +389,7 @@
 	if (err)
 		goto abort;
 	if (new)
-		bh_result->b_state |= (1UL << BH_New);
+		set_buffer_new(bh_result);
 	map_bh(bh_result, sb, phys);
 abort:
 	unlock_kernel();
@@ -419,7 +419,7 @@
 		bh = sb_getblk(inode->i_sb, dummy.b_blocknr);
 		if (buffer_new(&dummy)) {
 			memset(bh->b_data, 0, inode->i_sb->s_blocksize);
-			mark_buffer_uptodate(bh, 1);
+			set_buffer_uptodate(bh);
 			mark_buffer_dirty(bh);
 		}
 		return bh;
diff -Nru a/fs/ufs/util.c b/fs/ufs/util.c
--- a/fs/ufs/util.c	Tue Apr 30 17:10:25 2002
+++ b/fs/ufs/util.c	Tue Apr 30 17:10:25 2002
@@ -109,8 +109,13 @@
 	unsigned i;
 	if (!ubh)
 		return;
-	for ( i = 0; i < ubh->count; i++ )
-		mark_buffer_uptodate (ubh->bh[i], flag);
+	if (flag) {
+		for ( i = 0; i < ubh->count; i++ )
+			set_buffer_uptodate (ubh->bh[i]);
+	} else {
+		for ( i = 0; i < ubh->count; i++ )
+			clear_buffer_uptodate (ubh->bh[i]);
+	}
 }
 
 void ubh_ll_rw_block (int rw, unsigned nr, struct ufs_buffer_head * ubh[])
diff -Nru a/fs/umsdos/dir.c b/fs/umsdos/dir.c
--- a/fs/umsdos/dir.c	Tue Apr 30 17:10:25 2002
+++ b/fs/umsdos/dir.c	Tue Apr 30 17:10:25 2002
@@ -17,6 +17,7 @@
 #include <linux/umsdos_fs.h>
 #include <linux/slab.h>
 #include <linux/pagemap.h>
+#include <linux/smp_lock.h>
 
 #define UMSDOS_SPECIAL_DIRFPOS	3
 extern struct dentry *saved_root;
@@ -302,6 +303,8 @@
 	int ret = 0, count = 0;
 	struct UMSDOS_DIR_ONCE bufk;
 
+	lock_kernel();
+
 	bufk.dirbuf = dirbuf;
 	bufk.filldir = filldir;
 	bufk.stop = 0;
@@ -317,6 +320,7 @@
 			break;
 		count += bufk.count;
 	}
+	unlock_kernel();
 	Printk (("UMSDOS_readdir out %d count %d pos %Ld\n", 
 		ret, count, filp->f_pos));
 	return count ? : ret;
@@ -692,8 +696,8 @@
 	dentry_dst=(struct dentry *)page;
 	if (IS_ERR(page))
 		goto out;
-	wait_on_page(page);
-	if (!Page_Uptodate(page))
+	wait_on_page_locked(page);
+	if (!PageUptodate(page))
 		goto async_fail;
 
 	dentry_dst = ERR_PTR(-ENOMEM);
diff -Nru a/fs/umsdos/emd.c b/fs/umsdos/emd.c
--- a/fs/umsdos/emd.c	Tue Apr 30 17:10:25 2002
+++ b/fs/umsdos/emd.c	Tue Apr 30 17:10:25 2002
@@ -139,8 +139,8 @@
 			(filler_t*)mapping->a_ops->readpage, NULL);
 	if (IS_ERR(page))
 		goto sync_fail;
-	wait_on_page(page);
-	if (!Page_Uptodate(page))
+	wait_on_page_locked(page);
+	if (!PageUptodate(page))
 		goto async_fail;
 	p = (struct umsdos_dirent*)(kmap(page)+offs);
 
@@ -165,8 +165,8 @@
 			page = page2;
 			goto sync_fail;
 		}
-		wait_on_page(page2);
-		if (!Page_Uptodate(page2)) {
+		wait_on_page_locked(page2);
+		if (!PageUptodate(page2)) {
 			kunmap(page);
 			page_cache_release(page2);
 			goto async_fail;
@@ -276,7 +276,7 @@
 			goto out_unlock3;
 		ret = mapping->a_ops->commit_write(NULL,page,offs,
 					PAGE_CACHE_SIZE);
-		UnlockPage(page2);
+		unlock_page(page2);
 		page_cache_release(page2);
 		if (ret)
 			goto out_unlock;
@@ -292,7 +292,7 @@
 		if (ret)
 			goto out_unlock;
 	}
-	UnlockPage(page);
+	unlock_page(page);
 	page_cache_release(page);
 		
 	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
@@ -304,13 +304,13 @@
 	Printk (("umsdos_writeentry /mn/: returning %d...\n", ret));
 	return ret;
 out_unlock3:
-	UnlockPage(page2);
+	unlock_page(page2);
 	page_cache_release(page2);
 out_unlock2:
 	ClearPageUptodate(page);
 	kunmap(page);
 out_unlock:
-	UnlockPage(page);
+	unlock_page(page);
 	page_cache_release(page);
 	printk ("UMSDOS:  problem with EMD file:  can't write\n");
 	goto out_dput;
@@ -392,8 +392,8 @@
 			page = read_cache_page(mapping,index,readpage,NULL);
 			if (IS_ERR(page))
 				goto sync_fail;
-			wait_on_page(page);
-			if (!Page_Uptodate(page))
+			wait_on_page_locked(page);
+			if (!PageUptodate(page))
 				goto async_fail;
 			p = kmap(page);
 		}
@@ -441,8 +441,8 @@
 				page = next_page;
 				goto sync_fail;
 			}
-			wait_on_page(next_page);
-			if (!Page_Uptodate(next_page)) {
+			wait_on_page_locked(next_page);
+			if (!PageUptodate(next_page)) {
 				page_cache_release(page);
 				page = next_page;
 				goto async_fail;
diff -Nru a/fs/umsdos/inode.c b/fs/umsdos/inode.c
--- a/fs/umsdos/inode.c	Tue Apr 30 17:10:23 2002
+++ b/fs/umsdos/inode.c	Tue Apr 30 17:10:23 2002
@@ -300,7 +300,7 @@
 	 * EMD file. The msdos fs is not even called.
 	 */
 out_unlock:
-	UnlockPage(page);
+	unlock_page(page);
 	page_cache_release(page);
 out_dput:
 	dput(demd);
diff -Nru a/fs/umsdos/rdir.c b/fs/umsdos/rdir.c
--- a/fs/umsdos/rdir.c	Tue Apr 30 17:10:25 2002
+++ b/fs/umsdos/rdir.c	Tue Apr 30 17:10:25 2002
@@ -15,6 +15,7 @@
 #include <linux/limits.h>
 #include <linux/umsdos_fs.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 
@@ -63,11 +64,15 @@
 {
 	struct inode *dir = filp->f_dentry->d_inode;
 	struct RDIR_FILLDIR bufk;
+	int ret;
 
+	lock_kernel();
 	bufk.filldir = filldir;
 	bufk.dirbuf = dirbuf;
 	bufk.real_root = pseudo_root && (dir == saved_root->d_inode);
-	return fat_readdir (filp, &bufk, rdir_filldir);
+	ret = fat_readdir (filp, &bufk, rdir_filldir);
+	unlock_kernel();
+	return ret;
 }
 
 
diff -Nru a/include/linux/amigaffs.h b/include/linux/amigaffs.h
--- a/include/linux/amigaffs.h	Tue Apr 30 17:10:24 2002
+++ b/include/linux/amigaffs.h	Tue Apr 30 17:10:24 2002
@@ -50,7 +50,7 @@
 		bh = sb_getblk(sb, block);
 		lock_buffer(bh);
 		memset(bh->b_data, 0 , sb->s_blocksize);
-		mark_buffer_uptodate(bh, 1);
+		set_buffer_uptodate(bh);
 		unlock_buffer(bh);
 		return bh;
 	}
@@ -64,7 +64,7 @@
 	if (block >= AFFS_SB(sb)->s_reserved && block < AFFS_SB(sb)->s_partition_size) {
 		bh = sb_getblk(sb, block);
 		wait_on_buffer(bh);
-		mark_buffer_uptodate(bh, 1);
+		set_buffer_uptodate(bh);
 		return bh;
 	}
 	return NULL;
diff -Nru a/include/linux/blkdev.h b/include/linux/blkdev.h
--- a/include/linux/blkdev.h	Tue Apr 30 17:10:25 2002
+++ b/include/linux/blkdev.h	Tue Apr 30 17:10:25 2002
@@ -150,9 +150,9 @@
 
 	/*
 	 * The VM-level readahead tunable for this device.  In
-	 * units of 512-byte sectors.
+	 * units of PAGE_CACHE_SIZE pages.
 	 */
-	unsigned ra_sectors;
+	unsigned long ra_pages;
 
 	/*
 	 * The queue owner gets to use this for whatever they like.
@@ -310,8 +310,7 @@
 extern void blk_queue_segment_boundary(request_queue_t *q, unsigned long);
 extern void blk_queue_assign_lock(request_queue_t *q, spinlock_t *);
 extern void blk_queue_prep_rq(request_queue_t *q, prep_rq_fn *pfn);
-extern int blk_set_readahead(struct block_device *bdev, unsigned sectors);
-extern unsigned blk_get_readahead(struct block_device *bdev);
+extern unsigned long *blk_get_ra_pages(kdev_t kdev);
 
 extern int blk_rq_map_sg(request_queue_t *, struct request *, struct scatterlist *);
 extern void blk_dump_rq_flags(struct request *, char *);
diff -Nru a/include/linux/buffer_head.h b/include/linux/buffer_head.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/buffer_head.h	Tue Apr 30 17:10:25 2002
@@ -0,0 +1,315 @@
+/*
+ * include/linux/buffer_head.h
+ *
+ * Everything to do with buffer_head.b_state.
+ */
+
+#ifndef BUFFER_FLAGS_H
+#define BUFFER_FLAGS_H
+
+/* bh state bits */
+enum bh_state_bits {
+	BH_Uptodate,	/* 1 if the buffer contains valid data */
+	BH_Dirty,	/* 1 if the buffer is dirty */
+	BH_Lock,	/* 1 if the buffer is locked */
+	BH_Req,		/* 0 if the buffer has been invalidated */
+
+	BH_Mapped,	/* 1 if the buffer has a disk mapping */
+	BH_New,		/* 1 if the buffer is new and not yet written out */
+	BH_Async,	/* 1 if the buffer is under end_buffer_io_async I/O */
+	BH_JBD,		/* 1 if it has an attached journal_head */
+
+	BH_PrivateStart,/* not a state bit, but the first bit available
+			 * for private allocation by other entities
+			 */
+};
+
+#define MAX_BUF_PER_PAGE (PAGE_CACHE_SIZE / 512)
+
+struct page;
+struct kiobuf;
+struct buffer_head;
+typedef void (bh_end_io_t)(struct buffer_head *bh, int uptodate);
+
+/*
+ * Try to keep the most commonly used fields in single cache lines (16
+ * bytes) to improve performance.  This ordering should be
+ * particularly beneficial on 32-bit processors.
+ * 
+ * We use the first 16 bytes for the data which is used in searches
+ * over the block hash lists (ie. getblk() and friends).
+ * 
+ * The second 16 bytes we use for lru buffer scans, as used by
+ * sync_buffers() and refill_freelist().  -- sct
+ */
+struct buffer_head {
+	/* First cache line: */
+	sector_t b_blocknr;		/* block number */
+	unsigned short b_size;		/* block size */
+	struct block_device *b_bdev;
+
+	atomic_t b_count;		/* users using this block */
+	unsigned long b_state;		/* buffer state bitmap (see above) */
+	struct buffer_head *b_this_page;/* circular list of page's buffers */
+	struct page *b_page;		/* the page this bh is mapped to */
+
+	char * b_data;			/* pointer to data block */
+	bh_end_io_t *b_end_io;		/* I/O completion */
+ 	void *b_private;		/* reserved for b_end_io */
+	struct list_head     b_inode_buffers; /* list of inode dirty buffers */
+};
+
+
+/*
+ * macro tricks to expand the set_buffer_foo(), clear_buffer_foo()
+ * and buffer_foo() functions.
+ */
+#define BUFFER_FNS(bit, name)						\
+static inline void set_buffer_##name(struct buffer_head *bh)		\
+{									\
+	set_bit(BH_##bit, &(bh)->b_state);				\
+}									\
+static inline void clear_buffer_##name(struct buffer_head *bh)		\
+{									\
+	clear_bit(BH_##bit, &(bh)->b_state);				\
+}									\
+static inline int buffer_##name(struct buffer_head *bh)			\
+{									\
+	return test_bit(BH_##bit, &(bh)->b_state);			\
+}
+
+/*
+ * test_set_buffer_foo() and test_clear_buffer_foo()
+ */
+#define TAS_BUFFER_FNS(bit, name)					\
+static inline int test_set_buffer_##name(struct buffer_head *bh)	\
+{									\
+	return test_and_set_bit(BH_##bit, &(bh)->b_state);		\
+}									\
+static inline int test_clear_buffer_##name(struct buffer_head *bh)	\
+{									\
+	return test_and_clear_bit(BH_##bit, &(bh)->b_state);		\
+}									\
+
+BUFFER_FNS(Uptodate, uptodate)
+BUFFER_FNS(Dirty, dirty)
+TAS_BUFFER_FNS(Dirty, dirty)
+BUFFER_FNS(Lock, locked)
+TAS_BUFFER_FNS(Lock, locked)
+BUFFER_FNS(Req, req)
+BUFFER_FNS(Mapped, mapped)
+BUFFER_FNS(New, new)
+BUFFER_FNS(Async, async)
+
+/*
+ * Utility macros
+ */
+
+/*
+ * FIXME: this is used only by bh_kmap, which is used only by RAID5.
+ * Clean this up with blockdev-in-highmem infrastructure.
+ */
+#define bh_offset(bh)		((unsigned long)(bh)->b_data & ~PAGE_MASK)
+
+#define touch_buffer(bh)	mark_page_accessed(bh->b_page)
+
+/* If we *know* page->private refers to buffer_heads */
+#define page_buffers(page)					\
+	({							\
+		if (!PagePrivate(page))				\
+			BUG();					\
+		((struct buffer_head *)(page)->private);	\
+	})
+#define page_has_buffers(page)	PagePrivate(page)
+#define set_page_buffers(page, buffers)				\
+	do {							\
+		SetPagePrivate(page);				\
+		page->private = (unsigned long)buffers;		\
+	} while (0)
+#define clear_page_buffers(page)				\
+	do {							\
+		ClearPagePrivate(page);				\
+		page->private = 0;				\
+	} while (0)
+
+#define invalidate_buffers(dev)	__invalidate_buffers((dev), 0)
+#define destroy_buffers(dev)	__invalidate_buffers((dev), 1)
+
+
+/*
+ * Declarations
+ */
+
+void FASTCALL(mark_buffer_dirty(struct buffer_head *bh));
+void buffer_init(void);
+void init_buffer(struct buffer_head *, bh_end_io_t *, void *);
+void set_bh_page(struct buffer_head *bh,
+		struct page *page, unsigned long offset);
+int try_to_free_buffers(struct page *);
+void create_empty_buffers(struct page *, unsigned long,
+			unsigned long b_state);
+void end_buffer_io_sync(struct buffer_head *bh, int uptodate);
+void buffer_insert_list(spinlock_t *lock,
+			struct buffer_head *, struct list_head *);
+struct buffer_head *get_hash_table(kdev_t dev, sector_t block, int size);
+struct buffer_head *getblk(kdev_t dev, sector_t block, int size);
+struct buffer_head *bread(kdev_t dev, int block, int size);
+
+
+/* reiserfs_writepage needs this */
+void set_buffer_async_io(struct buffer_head *bh);
+void invalidate_inode_buffers(struct inode *);
+void invalidate_bdev(struct block_device *, int);
+void __invalidate_buffers(kdev_t dev, int);
+int sync_blockdev(struct block_device *bdev);
+void __wait_on_buffer(struct buffer_head *);
+void sleep_on_buffer(struct buffer_head *bh);
+void wake_up_buffer(struct buffer_head *bh);
+int fsync_dev(kdev_t);
+int fsync_bdev(struct block_device *);
+int fsync_super(struct super_block *);
+int fsync_no_super(struct block_device *);
+int fsync_buffers_list(spinlock_t *lock, struct list_head *);
+int inode_has_buffers(struct inode *);
+struct buffer_head *__get_hash_table(struct block_device *, sector_t, int);
+struct buffer_head * __getblk(struct block_device *, sector_t, int);
+void __brelse(struct buffer_head *);
+void __bforget(struct buffer_head *);
+struct buffer_head * __bread(struct block_device *, int, int);
+void wakeup_bdflush(void);
+struct buffer_head *alloc_buffer_head(int async);
+void free_buffer_head(struct buffer_head * bh);
+int brw_page(int, struct page *, struct block_device *, sector_t [], int);
+void FASTCALL(unlock_buffer(struct buffer_head *bh));
+
+/*
+ * Generic address_space_operations implementations for buffer_head-backed
+ * address_spaces.
+ */
+int try_to_release_page(struct page * page, int gfp_mask);
+int block_flushpage(struct page *page, unsigned long offset);
+int block_symlink(struct inode *, const char *, int);
+int block_write_full_page(struct page*, get_block_t*);
+int block_read_full_page(struct page*, get_block_t*);
+int block_prepare_write(struct page*, unsigned, unsigned, get_block_t*);
+int cont_prepare_write(struct page*, unsigned, unsigned, get_block_t*,
+				unsigned long *);
+int generic_cont_expand(struct inode *inode, loff_t size) ;
+int block_commit_write(struct page *page, unsigned from, unsigned to);
+int block_sync_page(struct page *);
+sector_t generic_block_bmap(struct address_space *, sector_t, get_block_t *);
+int generic_commit_write(struct file *, struct page *, unsigned, unsigned);
+int block_truncate_page(struct address_space *, loff_t, get_block_t *);
+int generic_direct_IO(int, struct inode *, struct kiobuf *,
+			unsigned long, int, get_block_t *);
+int file_fsync(struct file *, struct dentry *, int);
+
+#define OSYNC_METADATA	(1<<0)
+#define OSYNC_DATA	(1<<1)
+#define OSYNC_INODE	(1<<2)
+int generic_osync_inode(struct inode *, int);
+
+
+/*
+ * inline definitions
+ */
+
+static inline void get_bh(struct buffer_head * bh)
+{
+        atomic_inc(&(bh)->b_count);
+}
+
+static inline void put_bh(struct buffer_head *bh)
+{
+        smp_mb__before_atomic_dec();
+        atomic_dec(&bh->b_count);
+}
+
+static inline void
+mark_buffer_dirty_inode(struct buffer_head *bh, struct inode *inode)
+{
+	mark_buffer_dirty(bh);
+	buffer_insert_list(&inode->i_bufferlist_lock,
+			bh, &inode->i_dirty_buffers);
+}
+
+/*
+ * If an error happens during the make_request, this function
+ * has to be recalled. It marks the buffer as clean and not
+ * uptodate, and it notifys the upper layer about the end
+ * of the I/O.
+ */
+static inline void buffer_IO_error(struct buffer_head * bh)
+{
+	clear_buffer_dirty(bh);
+
+	/*
+	 * b_end_io has to clear the BH_Uptodate bitflag in the read error
+	 * case, however buffer contents are not necessarily bad if a
+	 * write fails
+	 */
+	bh->b_end_io(bh, buffer_uptodate(bh));
+}
+
+static inline int fsync_inode_buffers(struct inode *inode)
+{
+	return fsync_buffers_list(&inode->i_bufferlist_lock,
+				&inode->i_dirty_buffers);
+}
+
+static inline void brelse(struct buffer_head *buf)
+{
+	if (buf)
+		__brelse(buf);
+}
+
+static inline void bforget(struct buffer_head *buf)
+{
+	if (buf)
+		__bforget(buf);
+}
+
+static inline struct buffer_head * sb_bread(struct super_block *sb, int block)
+{
+	return __bread(sb->s_bdev, block, sb->s_blocksize);
+}
+
+static inline struct buffer_head * sb_getblk(struct super_block *sb, int block)
+{
+	return __getblk(sb->s_bdev, block, sb->s_blocksize);
+}
+
+static inline struct buffer_head *
+sb_get_hash_table(struct super_block *sb, int block)
+{
+	return __get_hash_table(sb->s_bdev, block, sb->s_blocksize);
+}
+
+static inline void
+map_bh(struct buffer_head *bh, struct super_block *sb, int block)
+{
+	set_buffer_mapped(bh);
+	bh->b_bdev = sb->s_bdev;
+	bh->b_blocknr = block;
+}
+
+static inline void wait_on_buffer(struct buffer_head * bh)
+{
+	if (buffer_locked(bh))
+		__wait_on_buffer(bh);
+}
+
+static inline void lock_buffer(struct buffer_head * bh)
+{
+	while (test_set_buffer_locked(bh))
+		__wait_on_buffer(bh);
+}
+
+/*
+ * Debug
+ */
+
+void __buffer_error(char *file, int line);
+#define buffer_error() __buffer_error(__FILE__, __LINE__)
+
+#endif		/* BUFFER_FLAGS_H */
diff -Nru a/include/linux/fs.h b/include/linux/fs.h
--- a/include/linux/fs.h	Tue Apr 30 17:10:25 2002
+++ b/include/linux/fs.h	Tue Apr 30 17:10:25 2002
@@ -112,6 +112,7 @@
 #define MS_MOVE		8192
 #define MS_REC		16384
 #define MS_VERBOSE	32768
+#define MS_FLUSHING	(1<<16)	/* inodes are currently under writeout */
 #define MS_ACTIVE	(1<<30)
 #define MS_NOUSER	(1<<31)
 
@@ -155,6 +156,7 @@
 #define IS_RDONLY(inode) ((inode)->i_sb->s_flags & MS_RDONLY)
 #define IS_SYNC(inode)		(__IS_FLG(inode, MS_SYNCHRONOUS) || ((inode)->i_flags & S_SYNC))
 #define IS_MANDLOCK(inode)	__IS_FLG(inode, MS_MANDLOCK)
+#define IS_FLUSHING(inode)	__IS_FLG(inode, MS_FLUSHING)
 
 #define IS_QUOTAINIT(inode)	((inode)->i_flags & S_QUOTA)
 #define IS_NOQUOTA(inode)	((inode)->i_flags & S_NOQUOTA)
@@ -204,104 +206,12 @@
 extern void update_atime (struct inode *);
 #define UPDATE_ATIME(inode) update_atime (inode)
 
-extern void buffer_init(unsigned long);
 extern void inode_init(unsigned long);
 extern void mnt_init(unsigned long);
 extern void files_init(unsigned long);
 
-/* bh state bits */
-enum bh_state_bits {
-	BH_Uptodate,	/* 1 if the buffer contains valid data */
-	BH_Dirty,	/* 1 if the buffer is dirty */
-	BH_Lock,	/* 1 if the buffer is locked */
-	BH_Req,		/* 0 if the buffer has been invalidated */
-	BH_Mapped,	/* 1 if the buffer has a disk mapping */
-	BH_New,		/* 1 if the buffer is new and not yet written out */
-	BH_Async,	/* 1 if the buffer is under end_buffer_io_async I/O */
-	BH_Wait_IO,	/* 1 if we should write out this buffer */
-	BH_launder,	/* 1 if we should throttle on this buffer */
-	BH_JBD,		/* 1 if it has an attached journal_head */
-
-	BH_PrivateStart,/* not a state bit, but the first bit available
-			 * for private allocation by other entities
-			 */
-};
-
-/*
- * Try to keep the most commonly used fields in single cache lines (16
- * bytes) to improve performance.  This ordering should be
- * particularly beneficial on 32-bit processors.
- * 
- * We use the first 16 bytes for the data which is used in searches
- * over the block hash lists (ie. getblk() and friends).
- * 
- * The second 16 bytes we use for lru buffer scans, as used by
- * sync_buffers() and refill_freelist().  -- sct
- */
-struct buffer_head {
-	/* First cache line: */
-	struct buffer_head *b_next;	/* Hash queue list */
-	sector_t b_blocknr;		/* block number */
-	unsigned short b_size;		/* block size */
-	unsigned short b_list;		/* List that this buffer appears */
-	struct block_device *b_bdev;
-
-	atomic_t b_count;		/* users using this block */
-	unsigned long b_state;		/* buffer state bitmap (see above) */
-	unsigned long b_flushtime;	/* Time when (dirty) buffer should be written */
-
-	struct buffer_head *b_next_free;/* lru/free list linkage */
-	struct buffer_head *b_prev_free;/* doubly linked list of buffers */
-	struct buffer_head *b_this_page;/* circular list of buffers in one page */
-	struct buffer_head **b_pprev;	/* doubly linked list of hash-queue */
-	char * b_data;			/* pointer to data block */
-	struct page *b_page;		/* the page this bh is mapped to */
-	void (*b_end_io)(struct buffer_head *bh, int uptodate); /* I/O completion */
- 	void *b_private;		/* reserved for b_end_io */
-
-	wait_queue_head_t b_wait;
-
-	int b_inode;				/* will go away */
-	struct list_head     b_inode_buffers;	/* doubly linked list of inode dirty buffers */
-};
-
-typedef void (bh_end_io_t)(struct buffer_head *bh, int uptodate);
-void init_buffer(struct buffer_head *, bh_end_io_t *, void *);
-
-#define __buffer_state(bh, state)	(((bh)->b_state & (1UL << BH_##state)) != 0)
-
-#define buffer_uptodate(bh)	__buffer_state(bh,Uptodate)
-#define buffer_dirty(bh)	__buffer_state(bh,Dirty)
-#define buffer_locked(bh)	__buffer_state(bh,Lock)
-#define buffer_req(bh)		__buffer_state(bh,Req)
-#define buffer_mapped(bh)	__buffer_state(bh,Mapped)
-#define buffer_new(bh)		__buffer_state(bh,New)
-#define buffer_async(bh)	__buffer_state(bh,Async)
-
-#define bh_offset(bh)		((unsigned long)(bh)->b_data & ~PAGE_MASK)
-
-extern void set_bh_page(struct buffer_head *bh, struct page *page, unsigned long offset);
-
-#define touch_buffer(bh)	mark_page_accessed(bh->b_page)
-
-/* If we *know* page->private refers to buffer_heads */
-#define page_buffers(page)					\
-	({							\
-		if (!PagePrivate(page))				\
-			BUG();					\
-		((struct buffer_head *)(page)->private);	\
-	})
-#define page_has_buffers(page)	PagePrivate(page)
-#define set_page_buffers(page, buffers)				\
-	do {							\
-		SetPagePrivate(page);				\
-		page->private = (unsigned long)buffers;		\
-	} while (0)
-#define clear_page_buffers(page)				\
-	do {							\
-		ClearPagePrivate(page);				\
-		page->private = 0;				\
-	} while (0)
+struct buffer_head;
+typedef int (get_block_t)(struct inode*,sector_t,struct buffer_head*,int);
 
 #include <linux/pipe_fs_i.h>
 /* #include <linux/umsdos_fs_i.h> */
@@ -371,6 +281,16 @@
 	int (*writepage)(struct page *);
 	int (*readpage)(struct file *, struct page *);
 	int (*sync_page)(struct page *);
+
+	/* Write back some dirty pages from this mapping. */
+	int (*writeback_mapping)(struct address_space *, int *nr_to_write);
+
+	/* Perform a writeback as a memory-freeing operation. */
+	int (*vm_writeback)(struct page *, int *nr_to_write);
+
+	/* Set a page dirty */
+	int (*set_page_dirty)(struct page *page);
+
 	/*
 	 * ext3 requires that a successful prepare_write() call be followed
 	 * by a commit_write() call - they must be balanced
@@ -391,13 +311,16 @@
 	struct list_head	clean_pages;	/* list of clean pages */
 	struct list_head	dirty_pages;	/* list of dirty pages */
 	struct list_head	locked_pages;	/* list of locked pages */
+	struct list_head	io_pages;	/* being prepared for I/O */
 	unsigned long		nrpages;	/* number of total pages */
 	struct address_space_operations *a_ops;	/* methods */
 	struct inode		*host;		/* owner: inode, block_device */
 	list_t			i_mmap;		/* list of private mappings */
 	list_t			i_mmap_shared;	/* list of private mappings */
 	spinlock_t		i_shared_lock;  /* and spinlock protecting it */
+	unsigned long		dirtied_when;	/* jiffies of first page dirtying */
 	int			gfp_mask;	/* how to allocate the pages */
+	unsigned long 		*ra_pages;	/* device readahead */
 };
 
 struct char_device {
@@ -426,9 +349,9 @@
 	struct list_head	i_hash;
 	struct list_head	i_list;
 	struct list_head	i_dentry;
-	
-	struct list_head	i_dirty_buffers;
-	struct list_head	i_dirty_data_buffers;
+
+	struct list_head	i_dirty_buffers;   /* uses i_bufferlist_lock */
+	spinlock_t		i_bufferlist_lock;
 
 	unsigned long		i_ino;
 	atomic_t		i_count;
@@ -513,6 +436,7 @@
 	unsigned long prev_page;	/* Cache last read() position */
 	unsigned long ahead_start;	/* Ahead window */
 	unsigned long ahead_size;
+	unsigned long ra_pages;		/* Maximum readahead window */
 };
 
 struct file {
@@ -654,6 +578,8 @@
 	struct qstr last;
 	unsigned int flags;
 	int last_type;
+	struct dentry *old_dentry;
+	struct vfsmount *old_mnt;
 };
 
 #define DQUOT_USR_ENABLED	0x01		/* User diskquotas enabled */
@@ -679,7 +605,6 @@
 
 #include <linux/ext3_fs_sb.h>
 #include <linux/hpfs_fs_sb.h>
-#include <linux/sysv_fs_sb.h>
 #include <linux/ufs_fs_sb.h>
 #include <linux/romfs_fs_sb.h>
 #include <linux/adfs_fs_sb.h>
@@ -693,8 +618,9 @@
 	struct list_head	s_list;		/* Keep this first */
 	kdev_t			s_dev;
 	unsigned long		s_blocksize;
-	unsigned char		s_blocksize_bits;
 	unsigned long		s_old_blocksize;
+	unsigned short		s_writeback_gen;/* To avoid writeback livelock */
+	unsigned char		s_blocksize_bits;
 	unsigned char		s_dirt;
 	unsigned long long	s_maxbytes;	/* Max file size */
 	struct file_system_type	*s_type;
@@ -723,7 +649,6 @@
 	union {
 		struct ext3_sb_info	ext3_sb;
 		struct hpfs_sb_info	hpfs_sb;
-		struct sysv_sb_info	sysv_sb;
 		struct ufs_sb_info	ufs_sb;
 		struct romfs_sb_info	romfs_sb;
 		struct adfs_sb_info	adfs_sb;
@@ -899,7 +824,7 @@
 	int (*show_options)(struct seq_file *, struct vfsmount *);
 };
 
-/* Inode state bits.. */
+/* Inode state bits.  Protected by inode_lock. */
 #define I_DIRTY_SYNC		1 /* Not dirty enough for O_DATASYNC */
 #define I_DIRTY_DATASYNC	2 /* Data-related inode changes pending */
 #define I_DIRTY_PAGES		4 /* Data-related inode changes pending */
@@ -920,11 +845,6 @@
 	__mark_inode_dirty(inode, I_DIRTY_SYNC);
 }
 
-static inline void mark_inode_dirty_pages(struct inode *inode)
-{
-	__mark_inode_dirty(inode, I_DIRTY_PAGES);
-}
-
 struct dquot_operations {
 	void (*initialize) (struct inode *, short);
 	void (*drop) (struct inode *);
@@ -1211,96 +1131,6 @@
 
 extern int fs_may_remount_ro(struct super_block *);
 
-extern int try_to_free_buffers(struct page *, unsigned int);
-extern void refile_buffer(struct buffer_head * buf);
-extern void create_empty_buffers(struct page *, unsigned long);
-extern void end_buffer_io_sync(struct buffer_head *bh, int uptodate);
-
-/* reiserfs_writepage needs this */
-extern void set_buffer_async_io(struct buffer_head *bh) ;
-
-#define BUF_CLEAN	0
-#define BUF_LOCKED	1	/* Buffers scheduled for write */
-#define BUF_DIRTY	2	/* Dirty buffers, not yet scheduled for write */
-#define NR_LIST		3
-
-static inline void get_bh(struct buffer_head * bh)
-{
-        atomic_inc(&(bh)->b_count);
-}
-
-static inline void put_bh(struct buffer_head *bh)
-{
-        smp_mb__before_atomic_dec();
-        atomic_dec(&bh->b_count);
-}
-
-/*
- * This is called by bh->b_end_io() handlers when I/O has completed.
- */
-static inline void mark_buffer_uptodate(struct buffer_head * bh, int on)
-{
-	if (on)
-		set_bit(BH_Uptodate, &bh->b_state);
-	else
-		clear_bit(BH_Uptodate, &bh->b_state);
-}
-
-#define atomic_set_buffer_clean(bh) test_and_clear_bit(BH_Dirty, &(bh)->b_state)
-
-static inline void __mark_buffer_clean(struct buffer_head *bh)
-{
-	refile_buffer(bh);
-}
-
-static inline void mark_buffer_clean(struct buffer_head * bh)
-{
-	if (atomic_set_buffer_clean(bh))
-		__mark_buffer_clean(bh);
-}
-
-extern void FASTCALL(__mark_dirty(struct buffer_head *bh));
-extern void FASTCALL(__mark_buffer_dirty(struct buffer_head *bh));
-extern void FASTCALL(mark_buffer_dirty(struct buffer_head *bh));
-extern void FASTCALL(buffer_insert_list(struct buffer_head *, struct list_head *));
-
-static inline void buffer_insert_inode_queue(struct buffer_head *bh, struct inode *inode)
-{
-	buffer_insert_list(bh, &inode->i_dirty_buffers);
-}
-static inline void buffer_insert_inode_data_queue(struct buffer_head *bh, struct inode *inode)
-{
-	buffer_insert_list(bh, &inode->i_dirty_data_buffers);
-}
-
-#define atomic_set_buffer_dirty(bh) test_and_set_bit(BH_Dirty, &(bh)->b_state)
-
-static inline void mark_buffer_async(struct buffer_head * bh, int on)
-{
-	if (on)
-		set_bit(BH_Async, &bh->b_state);
-	else
-		clear_bit(BH_Async, &bh->b_state);
-}
-
-/*
- * If an error happens during the make_request, this function
- * has to be recalled. It marks the buffer as clean and not
- * uptodate, and it notifys the upper layer about the end
- * of the I/O.
- */
-static inline void buffer_IO_error(struct buffer_head * bh)
-{
-	mark_buffer_clean(bh);
-
-	/*
-	 * b_end_io has to clear the BH_Uptodate bitflag in the read error
-	 * case, however buffer contents are not necessarily bad if a
-	 * write fails
-	 */
-	bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state));
-}
-
 /*
  * return READ, READA, or WRITE
  */
@@ -1311,46 +1141,14 @@
  */
 #define bio_data_dir(bio)	((bio)->bi_rw & 1)
 
-extern void buffer_insert_inode_queue(struct buffer_head *, struct inode *);
-static inline void mark_buffer_dirty_inode(struct buffer_head *bh, struct inode *inode)
-{
-	mark_buffer_dirty(bh);
-	buffer_insert_inode_queue(bh, inode);
-}
-
-extern void set_buffer_flushtime(struct buffer_head *);
-extern void balance_dirty(void);
 extern int check_disk_change(kdev_t);
 extern int invalidate_inodes(struct super_block *);
 extern int invalidate_device(kdev_t, int);
 extern void invalidate_inode_pages(struct inode *);
 extern void invalidate_inode_pages2(struct address_space *);
-extern void invalidate_inode_buffers(struct inode *);
-#define invalidate_buffers(dev)	__invalidate_buffers((dev), 0)
-#define destroy_buffers(dev)	__invalidate_buffers((dev), 1)
-extern void invalidate_bdev(struct block_device *, int);
-extern void __invalidate_buffers(kdev_t dev, int);
-extern void sync_inodes(void);
-extern void sync_unlocked_inodes(void);
 extern void write_inode_now(struct inode *, int);
-extern int sync_buffers(struct block_device *, int);
-extern int fsync_dev(kdev_t);
-extern int fsync_bdev(struct block_device *);
-extern int fsync_super(struct super_block *);
-extern int fsync_no_super(struct block_device *);
 extern void sync_inodes_sb(struct super_block *);
-extern int osync_buffers_list(struct list_head *);
-extern int fsync_buffers_list(struct list_head *);
-static inline int fsync_inode_buffers(struct inode *inode)
-{
-	return fsync_buffers_list(&inode->i_dirty_buffers);
-}
-static inline int fsync_inode_data_buffers(struct inode *inode)
-{
-	return fsync_buffers_list(&inode->i_dirty_data_buffers);
-}
-extern int inode_has_buffers(struct inode *);
-extern int filemap_fdatasync(struct address_space *);
+extern int filemap_fdatawrite(struct address_space *);
 extern int filemap_fdatawait(struct address_space *);
 extern void sync_supers(void);
 extern int bmap(struct inode *, int);
@@ -1395,7 +1193,6 @@
 #define LOOKUP_CONTINUE		(4)
 #define LOOKUP_PARENT		(16)
 #define LOOKUP_NOALT		(32)
-#define LOOKUP_LOCKED		(64)
 
 /*
  * Type of the last component on LOOKUP_PARENT
@@ -1449,6 +1246,7 @@
 	return iget4(sb, ino, NULL, NULL);
 }
 
+extern void __iget(struct inode * inode);
 extern void clear_inode(struct inode *);
 extern struct inode *new_inode(struct super_block *);
 extern void remove_suid(struct dentry *);
@@ -1456,115 +1254,14 @@
 extern void remove_inode_hash(struct inode *);
 extern struct file * get_empty_filp(void);
 extern void file_move(struct file *f, struct list_head *list);
-extern struct buffer_head * __get_hash_table(struct block_device *, sector_t, int);
-static inline struct buffer_head * get_hash_table(kdev_t dev, sector_t block, int size)
-{
-	struct block_device *bdev;
-	struct buffer_head *bh;
-	bdev = bdget(kdev_t_to_nr(dev));
-	if (!bdev) {
-		printk("No block device for %s\n", __bdevname(dev));
-		BUG();
-	}
-	bh = __get_hash_table(bdev, block, size);
-	atomic_dec(&bdev->bd_count);
-	return bh;
-}
-extern struct buffer_head * __getblk(struct block_device *, sector_t, int);
-static inline struct buffer_head * getblk(kdev_t dev, sector_t block, int size)
-{
-	struct block_device *bdev;
-	struct buffer_head *bh;
-	bdev = bdget(kdev_t_to_nr(dev));
-	if (!bdev) {
-		printk("No block device for %s\n", __bdevname(dev));
-		BUG();
-	}
-	bh = __getblk(bdev, block, size);
-	atomic_dec(&bdev->bd_count);
-	return bh;
-}
 extern void ll_rw_block(int, int, struct buffer_head * bh[]);
 extern int submit_bh(int, struct buffer_head *);
 struct bio;
 extern int submit_bio(int, struct bio *);
 extern int is_read_only(kdev_t);
-extern void __brelse(struct buffer_head *);
-static inline void brelse(struct buffer_head *buf)
-{
-	if (buf)
-		__brelse(buf);
-}
-extern void __bforget(struct buffer_head *);
-static inline void bforget(struct buffer_head *buf)
-{
-	if (buf)
-		__bforget(buf);
-}
 extern int set_blocksize(kdev_t, int);
 extern int sb_set_blocksize(struct super_block *, int);
 extern int sb_min_blocksize(struct super_block *, int);
-extern struct buffer_head * __bread(struct block_device *, int, int);
-static inline struct buffer_head * bread(kdev_t dev, int block, int size)
-{
-	struct block_device *bdev;
-	struct buffer_head *bh;
-	bdev = bdget(kdev_t_to_nr(dev));
-	if (!bdev) {
-		printk("No block device for %s\n", __bdevname(dev));
-		BUG();
-	}
-	bh = __bread(bdev, block, size);
-	atomic_dec(&bdev->bd_count);
-	return bh;
-}
-static inline struct buffer_head * sb_bread(struct super_block *sb, int block)
-{
-	return __bread(sb->s_bdev, block, sb->s_blocksize);
-}
-static inline struct buffer_head * sb_getblk(struct super_block *sb, int block)
-{
-	return __getblk(sb->s_bdev, block, sb->s_blocksize);
-}
-static inline struct buffer_head * sb_get_hash_table(struct super_block *sb, int block)
-{
-	return __get_hash_table(sb->s_bdev, block, sb->s_blocksize);
-}
-static inline void map_bh(struct buffer_head *bh, struct super_block *sb, int block)
-{
-	bh->b_state |= 1 << BH_Mapped;
-	bh->b_bdev = sb->s_bdev;
-	bh->b_blocknr = block;
-}
-extern void wakeup_bdflush(void);
-extern void put_unused_buffer_head(struct buffer_head * bh);
-extern struct buffer_head * get_unused_buffer_head(int async);
-
-extern int brw_page(int, struct page *, struct block_device *, sector_t [], int);
-
-typedef int (get_block_t)(struct inode*,sector_t,struct buffer_head*,int);
-
-/* Generic buffer handling for block filesystems.. */
-extern int try_to_release_page(struct page * page, int gfp_mask);
-extern int discard_bh_page(struct page *, unsigned long, int);
-#define block_flushpage(page, offset) discard_bh_page(page, offset, 1)
-#define block_invalidate_page(page) discard_bh_page(page, 0, 0)
-extern int block_symlink(struct inode *, const char *, int);
-extern int block_write_full_page(struct page*, get_block_t*);
-extern int block_read_full_page(struct page*, get_block_t*);
-extern int block_prepare_write(struct page*, unsigned, unsigned, get_block_t*);
-extern int cont_prepare_write(struct page*, unsigned, unsigned, get_block_t*,
-				unsigned long *);
-extern int generic_cont_expand(struct inode *inode, loff_t size) ;
-extern int block_commit_write(struct page *page, unsigned from, unsigned to);
-extern int block_sync_page(struct page *);
-
-sector_t generic_block_bmap(struct address_space *, sector_t, get_block_t *);
-int generic_commit_write(struct file *, struct page *, unsigned, unsigned);
-int block_truncate_page(struct address_space *, loff_t, get_block_t *);
-extern int generic_direct_IO(int, struct inode *, struct kiobuf *, unsigned long, int, get_block_t *);
-extern int waitfor_one_page(struct page *);
-extern int writeout_one_page(struct page *);
 
 extern int generic_file_mmap(struct file *, struct vm_area_struct *);
 extern int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size);
@@ -1576,6 +1273,8 @@
 extern loff_t remote_llseek(struct file *file, loff_t offset, int origin);
 extern int generic_file_open(struct inode * inode, struct file * filp);
 
+extern int generic_vm_writeback(struct page *page, int *nr_to_write);
+
 extern struct file_operations generic_ro_fops;
 
 extern int vfs_readlink(struct dentry *, char *, int, const char *);
@@ -1603,8 +1302,6 @@
 extern struct file_operations simple_dir_operations;
 extern struct inode_operations simple_dir_inode_operations;
 
-extern void show_buffers(void);
-
 #ifdef CONFIG_BLK_DEV_INITRD
 extern unsigned int real_root_dev;
 #endif
@@ -1614,13 +1311,6 @@
 extern ssize_t char_write(struct file *, const char *, size_t, loff_t *);
 extern ssize_t block_write(struct file *, const char *, size_t, loff_t *);
 
-extern int file_fsync(struct file *, struct dentry *, int);
-extern int generic_buffer_fdatasync(struct inode *inode, unsigned long start_idx, unsigned long end_idx);
-extern int generic_osync_inode(struct inode *, int);
-#define OSYNC_METADATA (1<<0)
-#define OSYNC_DATA (1<<1)
-#define OSYNC_INODE (1<<2)
-
 extern int inode_change_ok(struct inode *, struct iattr *);
 extern int inode_setattr(struct inode *, struct iattr *);
 
@@ -1632,6 +1322,8 @@
 	read_unlock(&dparent_lock);
 	return res;
 }
+
+#include <linux/buffer_head.h>
 
 #endif /* __KERNEL__ */
 
diff -Nru a/include/linux/fs_struct.h b/include/linux/fs_struct.h
--- a/include/linux/fs_struct.h	Tue Apr 30 17:10:24 2002
+++ b/include/linux/fs_struct.h	Tue Apr 30 17:10:24 2002
@@ -35,10 +35,12 @@
 	struct dentry *old_root;
 	struct vfsmount *old_rootmnt;
 	write_lock(&fs->lock);
+	spin_lock(&dcache_lock);
 	old_root = fs->root;
 	old_rootmnt = fs->rootmnt;
 	fs->rootmnt = mntget(mnt);
 	fs->root = dget(dentry);
+	spin_unlock(&dcache_lock);
 	write_unlock(&fs->lock);
 	if (old_root) {
 		dput(old_root);
@@ -58,10 +60,12 @@
 	struct dentry *old_pwd;
 	struct vfsmount *old_pwdmnt;
 	write_lock(&fs->lock);
+	spin_lock(&dcache_lock);
 	old_pwd = fs->pwd;
 	old_pwdmnt = fs->pwdmnt;
 	fs->pwdmnt = mntget(mnt);
 	fs->pwd = dget(dentry);
+	spin_unlock(&dcache_lock);
 	write_unlock(&fs->lock);
 	if (old_pwd) {
 		dput(old_pwd);
diff -Nru a/include/linux/hdreg.h b/include/linux/hdreg.h
--- a/include/linux/hdreg.h	Tue Apr 30 17:10:25 2002
+++ b/include/linux/hdreg.h	Tue Apr 30 17:10:25 2002
@@ -34,6 +34,7 @@
 #define ECC_STAT		0x04	/* Corrected error */
 #define DRQ_STAT		0x08
 #define SEEK_STAT		0x10
+#define SERVICE_STAT		SEEK_STAT
 #define WRERR_STAT		0x20
 #define READY_STAT		0x40
 #define BUSY_STAT		0x80
@@ -48,6 +49,13 @@
 #define ECC_ERR			0x40	/* Uncorrectable ECC error */
 #define BBD_ERR			0x80	/* pre-EIDE meaning:  block marked bad */
 #define ICRC_ERR		0x80	/* new meaning:  CRC error during transfer */
+
+/*
+ * sector count bits
+ */
+#define NSEC_CD			0x01
+#define NSEC_IO			0x02
+#define NSEC_REL		0x04
 
 /*
  * Command Header sizes for IOCTL commands
diff -Nru a/include/linux/ide.h b/include/linux/ide.h
--- a/include/linux/ide.h	Tue Apr 30 17:10:25 2002
+++ b/include/linux/ide.h	Tue Apr 30 17:10:25 2002
@@ -283,16 +283,10 @@
 	 */
 	request_queue_t	queue;	/* per device request queue */
 
-	struct ata_device	*next;	/* circular list of hwgroup drives */
-
 	/* Those are directly injected jiffie values. They should go away and
 	 * we should use generic timers instead!!!
 	 */
-
-	unsigned long PADAM_sleep;		/* sleep until this time */
-	unsigned long PADAM_service_start;	/* time we started last request */
-	unsigned long PADAM_service_time;	/* service time of last request */
-	unsigned long PADAM_timeout;		/* max time to wait for irq */
+	unsigned long PADAM_sleep;	/* sleep until this time */
 
 	/* Flags requesting/indicating one of the following special commands
 	 * executed on the request queue.
@@ -374,7 +368,7 @@
 } ide_drive_t;
 
 /*
- * An ide_dmaproc_t() initiates/aborts DMA read/write operations on a drive.
+ * This initiates/aborts DMA read/write operations on a drive.
  *
  * The caller is assumed to have selected the drive and programmed the drive's
  * sector address using CHS or LBA.  All that remains is to prepare for DMA
@@ -392,8 +386,6 @@
 		ide_dma_lostirq,			ide_dma_timeout
 } ide_dma_action_t;
 
-typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *);
-
 enum {
 	ATA_PRIMARY	= 0,
 	ATA_SECONDARY	= 1
@@ -446,7 +438,7 @@
 	void (*atapi_read)(ide_drive_t *, void *, unsigned int);
 	void (*atapi_write)(ide_drive_t *, void *, unsigned int);
 
-	ide_dmaproc_t	*dmaproc;	/* dma read/write/abort routine */
+	int (*udma)(ide_dma_action_t, struct ata_device *, struct request *); /* dma read/write/abort routine */
 	unsigned int	*dmatable_cpu;	/* dma physical region descriptor table (cpu view) */
 	dma_addr_t	dmatable_dma;	/* dma physical region descriptor table (dma view) */
 	struct scatterlist *sg_table;	/* Scatter-gather list used to build the above */
@@ -500,31 +492,25 @@
 } ide_startstop_t;
 
 /*
- *  Interrupt handler types.
+ *  Interrupt and timeout handler type.
  */
-struct ata_taskfile;
-typedef ide_startstop_t (ide_pre_handler_t)(ide_drive_t *, struct request *);
-typedef ide_startstop_t (ide_handler_t)(ide_drive_t *);
+typedef ide_startstop_t (ata_handler_t)(struct ata_device *, struct request *);
+typedef int (ata_expiry_t)(struct ata_device *, struct request *);
 
-/*
- * when ide_timer_expiry fires, invoke a handler of this type
- * to decide what to do.
- */
-typedef int (ide_expiry_t)(ide_drive_t *);
+struct ata_taskfile;
 
 #define IDE_BUSY	0	/* awaiting an interrupt */
 #define IDE_SLEEP	1
 #define IDE_DMA		2	/* DMA in progress */
 
 typedef struct hwgroup_s {
-	ide_handler_t *handler;		/* irq handler, if active */
+	ide_startstop_t (*handler)(struct ata_device *, struct request *);	/* irq handler, if active */
 	unsigned long flags;		/* BUSY, SLEEPING */
-	struct ata_device *drive;	/* current drive */
+	struct ata_device *XXX_drive;	/* current drive */
 	struct request *rq;		/* current request */
 	struct timer_list timer;	/* failsafe timer */
-	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 */
+	int (*expiry)(struct ata_device *, struct request *);	/* irq handler, if active */
 } ide_hwgroup_t;
 
 /* structure attached to the request for IDE_TASK_CMDS */
@@ -616,7 +602,7 @@
 	int (*cleanup)(struct ata_device *);
 	int (*standby)(struct ata_device *);
 	ide_startstop_t	(*do_request)(struct ata_device *, struct request *, sector_t);
-	int (*end_request)(struct ata_device *, int);
+	int (*end_request)(struct ata_device *, struct request *, int);
 
 	int (*ioctl)(struct ata_device *, struct inode *, struct file *, unsigned int, unsigned long);
 	int (*open)(struct inode *, struct file *, struct ata_device *);
@@ -663,14 +649,15 @@
 #define LOCAL_END_REQUEST	/* Don't generate end_request in blk.h */
 #include <linux/blk.h>
 
-extern int __ide_end_request(ide_drive_t *drive, int uptodate, int nr_secs);
-extern int ide_end_request(ide_drive_t *drive, int uptodate);
+extern int __ide_end_request(struct ata_device *, struct request *, int, int);
+extern int ide_end_request(struct ata_device *drive, struct request *, int);
 
 /*
  * This is used on exit from the driver, to designate the next irq handler
  * and also to start the safety timer.
  */
-void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout, ide_expiry_t *expiry);
+extern void ide_set_handler(struct ata_device *drive, ata_handler_t handler,
+		unsigned long timeout, ata_expiry_t expiry);
 
 /*
  * Error reporting, in human readable form (luxurious, but a memory hog).
@@ -687,7 +674,7 @@
  * 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, ata_handler_t handler);
 
 /*
  * ide_fixstring() cleans up and (optionally) byte-swaps a text string,
@@ -756,9 +743,9 @@
 struct ata_taskfile {
 	struct hd_drive_task_hdr taskfile;
 	struct hd_drive_hob_hdr  hobfile;
-	int			command_type;
-	ide_pre_handler_t	*prehandler;
-	ide_handler_t		*handler;
+	int command_type;
+	ide_startstop_t (*prehandler)(struct ata_device *, struct request *);
+	ide_startstop_t (*handler)(struct ata_device *, struct request *);
 };
 
 extern void ata_read(ide_drive_t *drive, void *buffer, unsigned int wcount);
@@ -774,10 +761,10 @@
  * Special Flagged Register Validation Caller
  */
 
-extern ide_startstop_t recal_intr(ide_drive_t *drive);
-extern ide_startstop_t set_geometry_intr(ide_drive_t *drive);
-extern ide_startstop_t set_multmode_intr(ide_drive_t *drive);
-extern ide_startstop_t task_no_data_intr(ide_drive_t *drive);
+extern ide_startstop_t recal_intr(struct ata_device *, struct request *);
+extern ide_startstop_t set_geometry_intr(struct ata_device *, struct request *);
+extern ide_startstop_t set_multmode_intr(struct ata_device *, struct request *);
+extern ide_startstop_t task_no_data_intr(struct ata_device *, struct request *);
 
 
 /* This is setting up all fields in args, which depend upon the command type.
@@ -871,9 +858,9 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA
 int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func);
 void ide_destroy_dmatable (ide_drive_t *drive);
-ide_startstop_t ide_dma_intr (ide_drive_t *drive);
+extern ide_startstop_t ide_dma_intr(struct ata_device *, struct request *);
 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_dmaproc (ide_dma_action_t func, struct ata_device *drive, struct request *);
 extern void ide_release_dma(struct ata_channel *hwif);
 extern void ide_setup_dma(struct ata_channel *hwif,
 		unsigned long dmabase, unsigned int num_ports) __init;
diff -Nru a/include/linux/jbd.h b/include/linux/jbd.h
--- a/include/linux/jbd.h	Tue Apr 30 17:10:25 2002
+++ b/include/linux/jbd.h	Tue Apr 30 17:10:25 2002
@@ -233,11 +233,8 @@
 	BH_JBDDirty,		/* 1 if buffer is dirty but journaled */
 };
 
-/* Return true if the buffer is one which JBD is managing */
-static inline int buffer_jbd(struct buffer_head *bh)
-{
-	return __buffer_state(bh, JBD);
-}
+BUFFER_FNS(JBD, jbd)
+BUFFER_FNS(JBDDirty, jbddirty)
 
 static inline struct buffer_head *jh2bh(struct journal_head *jh)
 {
@@ -838,7 +835,7 @@
 /* Return true if this bufer is dirty wrt the journal */
 static inline int buffer_jdirty(struct buffer_head *bh)
 {
-	return buffer_jbd(bh) && __buffer_state(bh, JBDDirty);
+	return buffer_jbd(bh) && buffer_jbddirty(bh);
 }
 
 /* Return true if it's a data buffer which journalling is managing */
diff -Nru a/include/linux/linkage.h b/include/linux/linkage.h
--- a/include/linux/linkage.h	Tue Apr 30 17:10:23 2002
+++ b/include/linux/linkage.h	Tue Apr 30 17:10:23 2002
@@ -17,14 +17,6 @@
 #define asmlinkage CPP_ASMLINKAGE
 #endif
 
-#define SYMBOL_NAME_STR(X) #X
-#define SYMBOL_NAME(X) X
-#ifdef __STDC__
-#define SYMBOL_NAME_LABEL(X) X##:
-#else
-#define SYMBOL_NAME_LABEL(X) X/**/:
-#endif
-
 #ifdef __arm__
 #define __ALIGN .align 0
 #define __ALIGN_STR ".align 0"
@@ -54,9 +46,9 @@
 #define ALIGN_STR __ALIGN_STR
 
 #define ENTRY(name) \
-  .globl SYMBOL_NAME(name); \
+  .globl name; \
   ALIGN; \
-  SYMBOL_NAME_LABEL(name)
+  name:
 
 #endif
 
diff -Nru a/include/linux/locks.h b/include/linux/locks.h
--- a/include/linux/locks.h	Tue Apr 30 17:10:25 2002
+++ b/include/linux/locks.h	Tue Apr 30 17:10:25 2002
@@ -9,26 +9,6 @@
 #endif
 
 /*
- * Buffer cache locking - note that interrupts may only unlock, not
- * lock buffers.
- */
-extern void __wait_on_buffer(struct buffer_head *);
-
-static inline void wait_on_buffer(struct buffer_head * bh)
-{
-	if (test_bit(BH_Lock, &bh->b_state))
-		__wait_on_buffer(bh);
-}
-
-static inline void lock_buffer(struct buffer_head * bh)
-{
-	while (test_and_set_bit(BH_Lock, &bh->b_state))
-		__wait_on_buffer(bh);
-}
-
-extern void FASTCALL(unlock_buffer(struct buffer_head *bh));
-
-/*
  * super-block locking. Again, interrupts may only unlock
  * a super-block (although even this isn't done right now.
  * nfs may need it).
diff -Nru a/include/linux/mm.h b/include/linux/mm.h
--- a/include/linux/mm.h	Tue Apr 30 17:10:23 2002
+++ b/include/linux/mm.h	Tue Apr 30 17:10:23 2002
@@ -154,7 +154,7 @@
 					   updated asynchronously */
 	struct list_head lru;		/* Pageout list, eg. active_list;
 					   protected by pagemap_lru_lock !! */
-	unsigned long private;		/* fs-private opaque data */
+	unsigned long private;		/* mapping-private opaque data */
 
 	/*
 	 * On machines where all RAM is mapped into kernel address space,
@@ -191,11 +191,6 @@
 #define set_page_count(p,v) 	atomic_set(&(p)->count, v)
 
 /*
- * Various page->flags bits:
- *
- * PG_reserved is set for special pages, which can never be swapped
- * out. Some of them might not even exist (eg empty_bad_page)...
- *
  * Multiple processes may "see" the same page. E.g. for untouched
  * mappings of /dev/null, all processes see the same page full of
  * zeroes, and text pages of executables and shared libraries have
@@ -224,8 +219,6 @@
  * page's address_space.  Usually, this is the address of a circular
  * list of the page's disk buffers.
  *
- * The PG_private bitflag is set if page->private contains a valid
- * value.
  * For pages belonging to inodes, the page->count is the number of
  * attaches, plus 1 if `private' contains something, plus one for
  * the page cache itself.
@@ -244,75 +237,13 @@
  *   to be written to disk,
  * - private pages which have been modified may need to be swapped out
  *   to swap space and (later) to be read back into memory.
- * During disk I/O, PG_locked is used. This bit is set before I/O
- * and reset when I/O completes. page_waitqueue(page) is a wait queue of all
- * tasks waiting for the I/O on this page to complete.
- * PG_uptodate tells whether the page's contents is valid.
- * When a read completes, the page becomes uptodate, unless a disk I/O
- * error happened.
- *
- * For choosing which pages to swap out, inode pages carry a
- * PG_referenced bit, which is set any time the system accesses
- * that page through the (mapping,index) hash table. This referenced
- * bit, together with the referenced bit in the page tables, is used
- * to manipulate page->age and move the page across the active,
- * inactive_dirty and inactive_clean lists.
- *
- * Note that the referenced bit, the page->lru list_head and the
- * active, inactive_dirty and inactive_clean lists are protected by
- * the pagemap_lru_lock, and *NOT* by the usual PG_locked bit!
- *
- * PG_skip is used on sparc/sparc64 architectures to "skip" certain
- * parts of the address space.
- *
- * PG_error is set to indicate that an I/O error occurred on this page.
- *
- * PG_arch_1 is an architecture specific page state bit.  The generic
- * code guarantees that this bit is cleared for a page when it first
- * is entered into the page cache.
- *
- * PG_highmem pages are not permanently mapped into the kernel virtual
- * address space, they need to be kmapped separately for doing IO on
- * the pages. The struct page (these bits with information) are always
- * mapped into kernel address space...
  */
-#define PG_locked		 0	/* Page is locked. Don't touch. */
-#define PG_error		 1
-#define PG_referenced		 2
-#define PG_uptodate		 3
-#define PG_dirty		 4
-#define PG_unused		 5
-#define PG_lru			 6
-#define PG_active		 7
-#define PG_slab			 8
-#define PG_skip			10
-#define PG_highmem		11
-#define PG_checked		12	/* kill me in 2.5.<early>. */
-#define PG_arch_1		13
-#define PG_reserved		14
-#define PG_launder		15	/* written out by VM pressure.. */
-
-#define PG_private		16	/* Has something at ->private */
-
-/* Make it prettier to test the above... */
-#define UnlockPage(page)	unlock_page(page)
-#define Page_Uptodate(page)	test_bit(PG_uptodate, &(page)->flags)
-#define SetPageUptodate(page)	set_bit(PG_uptodate, &(page)->flags)
-#define ClearPageUptodate(page)	clear_bit(PG_uptodate, &(page)->flags)
-#define PageDirty(page)		test_bit(PG_dirty, &(page)->flags)
-#define SetPageDirty(page)	set_bit(PG_dirty, &(page)->flags)
-#define ClearPageDirty(page)	clear_bit(PG_dirty, &(page)->flags)
-#define PageLocked(page)	test_bit(PG_locked, &(page)->flags)
-#define LockPage(page)		set_bit(PG_locked, &(page)->flags)
-#define TryLockPage(page)	test_and_set_bit(PG_locked, &(page)->flags)
-#define PageChecked(page)	test_bit(PG_checked, &(page)->flags)
-#define SetPageChecked(page)	set_bit(PG_checked, &(page)->flags)
-#define PageLaunder(page)	test_bit(PG_launder, &(page)->flags)
-#define SetPageLaunder(page)	set_bit(PG_launder, &(page)->flags)
-#define __SetPageReserved(page)	__set_bit(PG_reserved, &(page)->flags)
-#define SetPagePrivate(page)	set_bit(PG_private, &(page)->flags)
-#define ClearPagePrivate(page)	clear_bit(PG_private, &(page)->flags)
-#define PagePrivate(page)	test_bit(PG_private, &(page)->flags)
+
+/*
+ * FIXME: take this include out, include page-flags.h in
+ * files which need it (119 of them)
+ */
+#include <linux/page-flags.h>
 
 /*
  * The zone field is never updated after free_area_init_core()
@@ -368,43 +299,6 @@
 
 #endif /* CONFIG_HIGHMEM || WANT_PAGE_VIRTUAL */
 
-extern void FASTCALL(set_page_dirty(struct page *));
-
-/*
- * The first mb is necessary to safely close the critical section opened by the
- * TryLockPage(), the second mb is necessary to enforce ordering between
- * the clear_bit and the read of the waitqueue (to avoid SMP races with a
- * parallel wait_on_page).
- */
-#define PageError(page)		test_bit(PG_error, &(page)->flags)
-#define SetPageError(page)	set_bit(PG_error, &(page)->flags)
-#define ClearPageError(page)	clear_bit(PG_error, &(page)->flags)
-#define PageReferenced(page)	test_bit(PG_referenced, &(page)->flags)
-#define SetPageReferenced(page)	set_bit(PG_referenced, &(page)->flags)
-#define ClearPageReferenced(page)	clear_bit(PG_referenced, &(page)->flags)
-#define PageTestandClearReferenced(page)	test_and_clear_bit(PG_referenced, &(page)->flags)
-#define PageSlab(page)		test_bit(PG_slab, &(page)->flags)
-#define PageSetSlab(page)	set_bit(PG_slab, &(page)->flags)
-#define PageClearSlab(page)	clear_bit(PG_slab, &(page)->flags)
-#define PageReserved(page)	test_bit(PG_reserved, &(page)->flags)
-
-#define PageActive(page)	test_bit(PG_active, &(page)->flags)
-#define SetPageActive(page)	set_bit(PG_active, &(page)->flags)
-#define ClearPageActive(page)	clear_bit(PG_active, &(page)->flags)
-
-#define PageLRU(page)		test_bit(PG_lru, &(page)->flags)
-#define TestSetPageLRU(page)	test_and_set_bit(PG_lru, &(page)->flags)
-#define TestClearPageLRU(page)	test_and_clear_bit(PG_lru, &(page)->flags)
-
-#ifdef CONFIG_HIGHMEM
-#define PageHighMem(page)		test_bit(PG_highmem, &(page)->flags)
-#else
-#define PageHighMem(page)		0 /* needed to optimize away at compile time */
-#endif
-
-#define SetPageReserved(page)		set_bit(PG_reserved, &(page)->flags)
-#define ClearPageReserved(page)		clear_bit(PG_reserved, &(page)->flags)
-
 /*
  * Error return values for the *_nopage functions
  */
@@ -447,6 +341,26 @@
 int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start,
 		int len, int write, int force, struct page **pages, struct vm_area_struct **vmas);
 
+int __set_page_dirty_buffers(struct page *page);
+int __set_page_dirty_nobuffers(struct page *page);
+
+/*
+ * If the mapping doesn't provide a set_page_dirty a_op, then
+ * just fall through and assume that it wants buffer_heads.
+ * FIXME: make the method unconditional.
+ */
+static inline int set_page_dirty(struct page *page)
+{
+	if (page->mapping) {
+		int (*spd)(struct page *);
+
+		spd = page->mapping->a_ops->set_page_dirty;
+		if (spd)
+			return (*spd)(page);
+	}
+	return __set_page_dirty_buffers(page);
+}
+
 /*
  * On a two-level page table, this ends up being trivial. Thus the
  * inlining and the symmetry break with pte_alloc_map() that does all
@@ -468,14 +382,6 @@
 extern void si_meminfo(struct sysinfo * val);
 extern void swapin_readahead(swp_entry_t);
 
-extern struct address_space swapper_space;
-#define PageSwapCache(page) ((page)->mapping == &swapper_space)
-
-static inline int is_page_cache_freeable(struct page * page)
-{
-	return page_count(page) - !!PagePrivate(page) == 1;
-}
-
 extern int can_share_swap_page(struct page *);
 extern int remove_exclusive_swap_page(struct page *);
 
@@ -538,6 +444,10 @@
 extern int filemap_sync(struct vm_area_struct *, unsigned long,	size_t, unsigned int);
 extern struct page *filemap_nopage(struct vm_area_struct *, unsigned long, int);
 
+/* mm/page-writeback.c */
+int generic_writeback_mapping(struct address_space *mapping, int *nr_to_write);
+int write_one_page(struct page *page, int wait);
+
 /* readahead.c */
 #define VM_MAX_READAHEAD	128	/* kbytes */
 #define VM_MIN_READAHEAD	16	/* kbytes (includes current page) */
@@ -546,6 +456,7 @@
 void page_cache_readahead(struct file *file, unsigned long offset);
 void page_cache_readaround(struct file *file, unsigned long offset);
 void handle_ra_thrashing(struct file *file);
+extern unsigned long default_ra_pages;
 
 /* vma is the first one with  address < vma->vm_end,
  * and even  address < vma->vm_start. Have to extend vma. */
@@ -591,10 +502,8 @@
 
 extern struct vm_area_struct *find_extend_vma(struct mm_struct *mm, unsigned long addr);
 
-extern int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0);
-extern int pdflush_flush(unsigned long nr_pages);
-
 extern struct page * vmalloc_to_page(void *addr);
+extern unsigned long get_page_cache_size(void);
 
 #endif /* __KERNEL__ */
 
diff -Nru a/include/linux/mmzone.h b/include/linux/mmzone.h
--- a/include/linux/mmzone.h	Tue Apr 30 17:10:23 2002
+++ b/include/linux/mmzone.h	Tue Apr 30 17:10:23 2002
@@ -68,7 +68,7 @@
 	 * table, they should be so rare as to be outweighed by the
 	 * benefits from the saved space.
 	 *
-	 * __wait_on_page() and unlock_page() in mm/filemap.c, are the
+	 * __wait_on_page_locked() and unlock_page() in mm/filemap.c, are the
 	 * primary users of these fields, and in mm/page_alloc.c
 	 * free_area_init_core() performs the initialization of them.
 	 */
diff -Nru a/include/linux/page-flags.h b/include/linux/page-flags.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/page-flags.h	Tue Apr 30 17:10:25 2002
@@ -0,0 +1,218 @@
+/*
+ * Macros for manipulating and testing page->flags
+ */
+
+#ifndef PAGE_FLAGS_H
+#define PAGE_FLAGS_H
+
+/*
+ * Various page->flags bits:
+ *
+ * PG_reserved is set for special pages, which can never be swapped out. Some
+ * of them might not even exist (eg empty_bad_page)...
+ *
+ * The PG_private bitflag is set if page->private contains a valid value.
+ *
+ * During disk I/O, PG_locked_dontuse is used. This bit is set before I/O and
+ * reset when I/O completes. page_waitqueue(page) is a wait queue of all tasks
+ * waiting for the I/O on this page to complete.
+ *
+ * PG_uptodate tells whether the page's contents is valid.  When a read
+ * completes, the page becomes uptodate, unless a disk I/O error happened.
+ *
+ * For choosing which pages to swap out, inode pages carry a PG_referenced bit,
+ * which is set any time the system accesses that page through the (mapping,
+ * index) hash table.  This referenced bit, together with the referenced bit
+ * in the page tables, is used to manipulate page->age and move the page across
+ * the active, inactive_dirty and inactive_clean lists.
+ *
+ * Note that the referenced bit, the page->lru list_head and the active,
+ * inactive_dirty and inactive_clean lists are protected by the
+ * pagemap_lru_lock, and *NOT* by the usual PG_locked_dontuse bit!
+ *
+ * PG_error is set to indicate that an I/O error occurred on this page.
+ *
+ * PG_arch_1 is an architecture specific page state bit.  The generic code
+ * guarantees that this bit is cleared for a page when it first is entered into
+ * the page cache.
+ *
+ * PG_highmem pages are not permanently mapped into the kernel virtual address
+ * space, they need to be kmapped separately for doing IO on the pages.  The
+ * struct page (these bits with information) are always mapped into kernel
+ * address space...
+ */
+
+/*
+ * Don't use the *_dontuse flags.  Use the macros.  Otherwise you'll break
+ * locked- and dirty-page accounting.  The top eight bits of page->flags are
+ * used for page->zone, so putting flag bits there doesn't work.
+ */
+#define PG_locked_dontuse	 0	/* Page is locked. Don't touch. */
+#define PG_error		 1
+#define PG_referenced		 2
+#define PG_uptodate		 3
+
+#define PG_dirty_dontuse	 4
+#define PG_lru			 5
+#define PG_active		 6
+#define PG_slab			 7	/* slab debug (Suparna wants this) */
+
+#define PG_highmem		 8
+#define PG_checked		 9	/* kill me in 2.5.<early>. */
+#define PG_arch_1		10
+#define PG_reserved		11
+
+#define PG_launder		12	/* written out by VM pressure.. */
+#define PG_private		13	/* Has something at ->private */
+#define PG_writeback		14	/* Page is under writeback */
+
+/*
+ * Global page accounting.  One instance per CPU.
+ */
+extern struct page_state {
+	unsigned long nr_dirty;
+	unsigned long nr_locked;
+	unsigned long nr_pagecache;
+} ____cacheline_aligned_in_smp page_states[NR_CPUS];
+
+extern void get_page_state(struct page_state *ret);
+
+#define mod_page_state(member, delta)					\
+	do {								\
+		preempt_disable();					\
+		page_states[smp_processor_id()].member += (delta);	\
+		preempt_enable();					\
+	} while (0)
+
+#define inc_page_state(member)	mod_page_state(member, 1UL)
+#define dec_page_state(member)	mod_page_state(member, 0UL - 1)
+
+
+/*
+ * Manipulation of page state flags
+ */
+#define PageLocked(page)	test_bit(PG_locked_dontuse, &(page)->flags)
+#define SetPageLocked(page)						\
+	do {								\
+		if (!test_and_set_bit(PG_locked_dontuse,		\
+				&(page)->flags))			\
+			inc_page_state(nr_locked);			\
+	} while (0)
+#define TestSetPageLocked(page)						\
+	({								\
+		int ret;						\
+		ret = test_and_set_bit(PG_locked_dontuse,		\
+					&(page)->flags);		\
+		if (!ret)						\
+			inc_page_state(nr_locked);			\
+		ret;							\
+	})
+#define ClearPageLocked(page)						\
+	do {								\
+		if (test_and_clear_bit(PG_locked_dontuse,		\
+				&(page)->flags))			\
+			dec_page_state(nr_locked);			\
+	} while (0)
+#define TestClearPageLocked(page)					\
+	({								\
+		int ret;						\
+		ret = test_and_clear_bit(PG_locked_dontuse,		\
+				&(page)->flags);			\
+		if (ret)						\
+			dec_page_state(nr_locked);			\
+		ret;							\
+	})
+
+#define PageError(page)		test_bit(PG_error, &(page)->flags)
+#define SetPageError(page)	set_bit(PG_error, &(page)->flags)
+#define ClearPageError(page)	clear_bit(PG_error, &(page)->flags)
+
+#define PageReferenced(page)	test_bit(PG_referenced, &(page)->flags)
+#define SetPageReferenced(page)	set_bit(PG_referenced, &(page)->flags)
+#define ClearPageReferenced(page)	clear_bit(PG_referenced, &(page)->flags)
+#define TestClearPageReferenced(page) test_and_clear_bit(PG_referenced, &(page)->flags)
+
+#define PageUptodate(page)	test_bit(PG_uptodate, &(page)->flags)
+#define SetPageUptodate(page)	set_bit(PG_uptodate, &(page)->flags)
+#define ClearPageUptodate(page)	clear_bit(PG_uptodate, &(page)->flags)
+
+#define PageDirty(page)		test_bit(PG_dirty_dontuse, &(page)->flags)
+#define SetPageDirty(page)						\
+	do {								\
+		if (!test_and_set_bit(PG_dirty_dontuse,			\
+					&(page)->flags))		\
+			inc_page_state(nr_dirty);			\
+	} while (0)
+#define TestSetPageDirty(page)						\
+	({								\
+		int ret;						\
+		ret = test_and_set_bit(PG_dirty_dontuse,		\
+				&(page)->flags);			\
+		if (!ret)						\
+			inc_page_state(nr_dirty);			\
+		ret;							\
+	})
+#define ClearPageDirty(page)						\
+	do {								\
+		if (test_and_clear_bit(PG_dirty_dontuse,		\
+				&(page)->flags))			\
+			dec_page_state(nr_dirty);			\
+	} while (0)
+#define TestClearPageDirty(page)					\
+	({								\
+		int ret;						\
+		ret = test_and_clear_bit(PG_dirty_dontuse,		\
+				&(page)->flags);			\
+		if (ret)						\
+			dec_page_state(nr_dirty);			\
+		ret;							\
+	})
+
+#define PageLRU(page)		test_bit(PG_lru, &(page)->flags)
+#define TestSetPageLRU(page)	test_and_set_bit(PG_lru, &(page)->flags)
+#define TestClearPageLRU(page)	test_and_clear_bit(PG_lru, &(page)->flags)
+
+#define PageActive(page)	test_bit(PG_active, &(page)->flags)
+#define SetPageActive(page)	set_bit(PG_active, &(page)->flags)
+#define ClearPageActive(page)	clear_bit(PG_active, &(page)->flags)
+
+#define PageSlab(page)		test_bit(PG_slab, &(page)->flags)
+#define SetPageSlab(page)	set_bit(PG_slab, &(page)->flags)
+#define ClearPageSlab(page)	clear_bit(PG_slab, &(page)->flags)
+
+#ifdef CONFIG_HIGHMEM
+#define PageHighMem(page)	test_bit(PG_highmem, &(page)->flags)
+#else
+#define PageHighMem(page)	0 /* needed to optimize away at compile time */
+#endif
+
+#define PageChecked(page)	test_bit(PG_checked, &(page)->flags)
+#define SetPageChecked(page)	set_bit(PG_checked, &(page)->flags)
+
+#define PageReserved(page)	test_bit(PG_reserved, &(page)->flags)
+#define SetPageReserved(page)	set_bit(PG_reserved, &(page)->flags)
+#define ClearPageReserved(page)	clear_bit(PG_reserved, &(page)->flags)
+
+#define PageLaunder(page)	test_bit(PG_launder, &(page)->flags)
+#define SetPageLaunder(page)	set_bit(PG_launder, &(page)->flags)
+
+#define SetPagePrivate(page)	set_bit(PG_private, &(page)->flags)
+#define ClearPagePrivate(page)	clear_bit(PG_private, &(page)->flags)
+#define PagePrivate(page)	test_bit(PG_private, &(page)->flags)
+
+#define PageWriteback(page)	test_bit(PG_writeback, &(page)->flags)
+#define SetPageWriteback(page)	set_bit(PG_writeback, &(page)->flags)
+#define ClearPageWriteback(page) clear_bit(PG_writeback, &(page)->flags)
+#define TestSetPageWriteback(page)	\
+	test_and_set_bit(PG_writeback, &(page)->flags)
+#define TestClearPageWriteback(page)	\
+	test_and_clear_bit(PG_writeback, &(page)->flags)
+
+/*
+ * The PageSwapCache predicate doesn't use a PG_flag at this time,
+ * but it may again do so one day.
+ */
+extern struct address_space swapper_space;
+#define PageSwapCache(page) ((page)->mapping == &swapper_space)
+
+#endif	/* PAGE_FLAGS_H */
diff -Nru a/include/linux/pagemap.h b/include/linux/pagemap.h
--- a/include/linux/pagemap.h	Tue Apr 30 17:10:23 2002
+++ b/include/linux/pagemap.h	Tue Apr 30 17:10:23 2002
@@ -41,8 +41,6 @@
  */
 #define page_cache_entry(x)	virt_to_page(x)
 
-extern atomic_t page_cache_size; /* # of pages currently in the page cache */
-
 extern struct page * find_get_page(struct address_space *mapping,
 				unsigned long index);
 extern struct page * find_lock_page(struct address_space *mapping,
@@ -61,6 +59,7 @@
 		struct address_space *mapping, unsigned long index);
 extern int add_to_page_cache_unique(struct page *page,
 		struct address_space *mapping, unsigned long index);
+
 static inline void ___add_to_page_cache(struct page *page,
 		struct address_space *mapping, unsigned long index)
 {
@@ -69,21 +68,23 @@
 	page->index = index;
 
 	mapping->nrpages++;
-	atomic_inc(&page_cache_size);
+	inc_page_state(nr_pagecache);
 }
 
 extern void FASTCALL(lock_page(struct page *page));
 extern void FASTCALL(unlock_page(struct page *page));
+extern void end_page_writeback(struct page *page);
 
-extern void ___wait_on_page(struct page *);
+extern void ___wait_on_page_locked(struct page *);
 
-static inline void wait_on_page(struct page * page)
+static inline void wait_on_page_locked(struct page *page)
 {
 	if (PageLocked(page))
-		___wait_on_page(page);
+		___wait_on_page_locked(page);
 }
 
 extern void wake_up_page(struct page *);
+extern void wait_on_page_writeback(struct page *page);
 
 typedef int filler_t(void *, struct page*);
 
diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h
--- a/include/linux/pci_ids.h	Tue Apr 30 17:10:25 2002
+++ b/include/linux/pci_ids.h	Tue Apr 30 17:10:25 2002
@@ -1631,15 +1631,6 @@
 #define PCI_DEVICE_ID_INTEL_82380FB	0x124b
 #define PCI_DEVICE_ID_INTEL_82439	0x1250
 #define PCI_DEVICE_ID_INTEL_80960_RP	0x1960
-#define PCI_DEVICE_ID_INTEL_82371SB_0	0x7000
-#define PCI_DEVICE_ID_INTEL_82371SB_1	0x7010
-#define PCI_DEVICE_ID_INTEL_82371SB_2	0x7020
-#define PCI_DEVICE_ID_INTEL_82437VX	0x7030
-#define PCI_DEVICE_ID_INTEL_82439TX	0x7100
-#define PCI_DEVICE_ID_INTEL_82371AB_0	0x7110
-#define PCI_DEVICE_ID_INTEL_82371AB	0x7111
-#define PCI_DEVICE_ID_INTEL_82371AB_2	0x7112
-#define PCI_DEVICE_ID_INTEL_82371AB_3	0x7113
 #define PCI_DEVICE_ID_INTEL_82801AA_0	0x2410
 #define PCI_DEVICE_ID_INTEL_82801AA_1	0x2411
 #define PCI_DEVICE_ID_INTEL_82801AA_2	0x2412
@@ -1666,6 +1657,7 @@
 #define PCI_DEVICE_ID_INTEL_82801BA_9	0x244b
 #define PCI_DEVICE_ID_INTEL_82801BA_10	0x244c
 #define PCI_DEVICE_ID_INTEL_82801BA_11	0x244e
+#define PCI_DEVICE_ID_INTEL_82801E_9	0x245b
 #define PCI_DEVICE_ID_INTEL_82801CA_0	0x2480
 #define PCI_DEVICE_ID_INTEL_82801CA_2	0x2482
 #define PCI_DEVICE_ID_INTEL_82801CA_3	0x2483
@@ -1676,7 +1668,17 @@
 #define PCI_DEVICE_ID_INTEL_82801CA_10	0x248a
 #define PCI_DEVICE_ID_INTEL_82801CA_11	0x248b
 #define PCI_DEVICE_ID_INTEL_82801CA_12	0x248c
+#define PCI_DEVICE_ID_INTEL_82801DB_9	0x24cb
 #define PCI_DEVICE_ID_INTEL_80310	0x530d
+#define PCI_DEVICE_ID_INTEL_82371SB_0	0x7000
+#define PCI_DEVICE_ID_INTEL_82371SB_1	0x7010
+#define PCI_DEVICE_ID_INTEL_82371SB_2	0x7020
+#define PCI_DEVICE_ID_INTEL_82437VX	0x7030
+#define PCI_DEVICE_ID_INTEL_82439TX	0x7100
+#define PCI_DEVICE_ID_INTEL_82371AB_0	0x7110
+#define PCI_DEVICE_ID_INTEL_82371AB	0x7111
+#define PCI_DEVICE_ID_INTEL_82371AB_2	0x7112
+#define PCI_DEVICE_ID_INTEL_82371AB_3	0x7113
 #define PCI_DEVICE_ID_INTEL_82810_MC1	0x7120
 #define PCI_DEVICE_ID_INTEL_82810_IG1	0x7121
 #define PCI_DEVICE_ID_INTEL_82810_MC3	0x7122
diff -Nru a/include/linux/sched.h b/include/linux/sched.h
--- a/include/linux/sched.h	Tue Apr 30 17:10:23 2002
+++ b/include/linux/sched.h	Tue Apr 30 17:10:23 2002
@@ -368,8 +368,7 @@
 #define PF_MEMALLOC	0x00000800	/* Allocating memory */
 #define PF_MEMDIE	0x00001000	/* Killed for out-of-memory */
 #define PF_FREE_PAGES	0x00002000	/* per process page freeing */
-#define PF_NOIO		0x00004000	/* avoid generating further I/O */
-#define PF_FLUSHER	0x00008000	/* responsible for disk writeback */
+#define PF_FLUSHER	0x00004000	/* responsible for disk writeback */
 
 /*
  * Ptrace flags
diff -Nru a/include/linux/slab.h b/include/linux/slab.h
--- a/include/linux/slab.h	Tue Apr 30 17:10:25 2002
+++ b/include/linux/slab.h	Tue Apr 30 17:10:25 2002
@@ -70,7 +70,6 @@
 extern kmem_cache_t	*files_cachep;
 extern kmem_cache_t	*filp_cachep;
 extern kmem_cache_t	*dquot_cachep;
-extern kmem_cache_t	*bh_cachep;
 extern kmem_cache_t	*fs_cachep;
 extern kmem_cache_t	*sigact_cachep;
 extern kmem_cache_t	*bio_cachep;
diff -Nru a/include/linux/swap.h b/include/linux/swap.h
--- a/include/linux/swap.h	Tue Apr 30 17:10:23 2002
+++ b/include/linux/swap.h	Tue Apr 30 17:10:23 2002
@@ -97,10 +97,11 @@
 
 extern unsigned int nr_free_pages(void);
 extern unsigned int nr_free_buffer_pages(void);
+extern unsigned int nr_free_pagecache_pages(void);
+extern unsigned long nr_buffermem_pages(void);
 extern int nr_active_pages;
 extern int nr_inactive_pages;
 extern atomic_t nr_async_pages;
-extern atomic_t page_cache_size;
 extern atomic_t buffermem_pages;
 extern spinlock_t pagecache_lock;
 extern void __remove_inode_page(struct page *);
diff -Nru a/include/linux/synclink.h b/include/linux/synclink.h
--- a/include/linux/synclink.h	Tue Apr 30 17:10:25 2002
+++ b/include/linux/synclink.h	Tue Apr 30 17:10:25 2002
@@ -1,17 +1,17 @@
 /*
  * SyncLink Multiprotocol Serial Adapter Driver
  *
- * $Id: synclink.h,v 3.5 2001/03/26 17:04:36 ez Exp $
+ * $Id: synclink.h,v 3.6 2002/02/20 21:58:20 paulkf Exp $
  *
  * Copyright (C) 1998-2000 by Microgate Corporation
- * 
- * Redistribution of this file is permitted under 
+ *
+ * Redistribution of this file is permitted under
  * the terms of the GNU Public License (GPL)
  */
 
 #ifndef _SYNCLINK_H_
 #define _SYNCLINK_H_
-#define SYNCLINK_H_VERSION 3.5
+#define SYNCLINK_H_VERSION 3.6
 
 #define BOOLEAN int
 #define TRUE 1
@@ -128,13 +128,18 @@
 #define MGSL_BUS_TYPE_EISA	2
 #define MGSL_BUS_TYPE_PCI	5
 
+#define MGSL_INTERFACE_DISABLE  0
+#define MGSL_INTERFACE_RS232    1
+#define MGSL_INTERFACE_V35      2
+#define MGSL_INTERFACE_RS422    3
+
 typedef struct _MGSL_PARAMS
 {
 	/* Common */
 
 	unsigned long	mode;		/* Asynchronous or HDLC */
 	unsigned char	loopback;	/* internal loopback mode */
-	
+
 	/* HDLC Only */
 
 	unsigned short	flags;
@@ -247,6 +252,8 @@
  * MGSL_IOCGSTATS	return current statistics
  * MGSL_IOCWAITEVENT	wait for specified event to occur
  * MGSL_LOOPTXDONE	transmit in HDLC LoopMode done
+ * MGSL_IOCSIF          set the serial interface type
+ * MGSL_IOCGIF          get the serial interface type
  */
 #define MGSL_MAGIC_IOC	'm'
 #define MGSL_IOCSPARAMS		_IOW(MGSL_MAGIC_IOC,0,struct _MGSL_PARAMS)
@@ -260,5 +267,7 @@
 #define MGSL_IOCWAITEVENT	_IOWR(MGSL_MAGIC_IOC,8,int)
 #define MGSL_IOCCLRMODCOUNT	_IO(MGSL_MAGIC_IOC,15)
 #define MGSL_IOCLOOPTXDONE	_IO(MGSL_MAGIC_IOC,9)
+#define MGSL_IOCSIF		_IO(MGSL_MAGIC_IOC,10)
+#define MGSL_IOCGIF		_IO(MGSL_MAGIC_IOC,11)
 
 #endif /* _SYNCLINK_H_ */
diff -Nru a/include/linux/sysctl.h b/include/linux/sysctl.h
--- a/include/linux/sysctl.h	Tue Apr 30 17:10:23 2002
+++ b/include/linux/sysctl.h	Tue Apr 30 17:10:23 2002
@@ -133,7 +133,7 @@
 	VM_SWAPCTL=1,		/* struct: Set vm swapping control */
 	VM_SWAPOUT=2,		/* int: Linear or sqrt() swapout for hogs */
 	VM_FREEPG=3,		/* struct: Set free page thresholds */
-	VM_BDFLUSH=4,		/* struct: Control buffer cache flushing */
+	VM_BDFLUSH_UNUSED=4,	/* Spare */
 	VM_OVERCOMMIT_MEMORY=5,	/* Turn off the virtual memory safety limit */
 	VM_BUFFERMEM=6,		/* struct: Set buffer memory thresholds */
 	VM_PAGECACHE=7,		/* struct: Set cache memory thresholds */
diff -Nru a/include/linux/sysv_fs.h b/include/linux/sysv_fs.h
--- a/include/linux/sysv_fs.h	Tue Apr 30 17:10:25 2002
+++ b/include/linux/sysv_fs.h	Tue Apr 30 17:10:25 2002
@@ -1,69 +1,21 @@
 #ifndef _LINUX_SYSV_FS_H
 #define _LINUX_SYSV_FS_H
 
-/*
- * The SystemV/Coherent filesystem constants/structures/macros
- */
-
-
-/* This code assumes
-   - sizeof(short) = 2, sizeof(int) = 4, sizeof(long) = 4,
-   - alignof(short) = 2, alignof(long) = 4.
-*/
-
-#ifdef __GNUC__
-#define __packed2__  __attribute__ ((packed, aligned(2)))
+#if defined(__GNUC__)
+# define __packed2__	__attribute__((packed, aligned(2)))
 #else
-#error I want gcc!
+>> I want to scream! <<
 #endif
 
-#include <linux/stat.h>		/* declares S_IFLNK etc. */
-#include <linux/sched.h>	/* declares wake_up() */
-#include <linux/sysv_fs_sb.h>	/* defines the sv_... shortcuts */
-
-/* temporary hack. */
-#include <linux/sysv_fs_i.h>
-static inline struct sysv_inode_info *SYSV_I(struct inode *inode)
-{
-	/* I think list_entry should have a more descriptive name..  --hch */
-	return list_entry(inode, struct sysv_inode_info, vfs_inode);
-}
-/* end temporary hack. */
-
-
-/* Layout on disk */
-/* ============== */
-
-static inline u32 PDP_swab(u32 x)
-{
-#ifdef __LITTLE_ENDIAN
-	return ((x & 0xffff) << 16) | ((x & 0xffff0000) >> 16);
-#else
-#ifdef __BIG_ENDIAN
-	return ((x & 0xff00ff) << 8) | ((x & 0xff00ff00) >> 8);
-#else
-#error BYTESEX
-#endif
-#endif
-}
 
 /* inode numbers are 16 bit */
-
 typedef u16 sysv_ino_t;
 
 /* Block numbers are 24 bit, sometimes stored in 32 bit.
    On Coherent FS, they are always stored in PDP-11 manner: the least
-   significant 16 bits come last.
-*/
-
+   significant 16 bits come last. */
 typedef u32 sysv_zone_t;
 
-/* Among the blocks ... */
-/* Xenix FS, Coherent FS: block 0 is the boot block, block 1 the super-block.
-   SystemV FS: block 0 contains both the boot sector and the super-block. */
-/* The first inode zone is sb->sv_firstinodezone (1 or 2). */
-
-/* Among the inodes ... */
 /* 0 is non-existent */
 #define SYSV_BADBL_INO	1	/* inode of bad blocks file */
 #define SYSV_ROOT_INO	2	/* inode of root directory */
@@ -101,7 +53,8 @@
 								
 };
 
-/* SystemV FS comes in two variants:
+/*
+ * SystemV FS comes in two variants:
  * sysv2: System V Release 2 (e.g. Microport), structure elements aligned(2).
  * sysv4: System V Release 4 (e.g. Consensys), structure elements aligned(4).
  */
@@ -223,51 +176,21 @@
 };
 
 /* SystemV/Coherent inode data on disk */
-
 struct sysv_inode {
 	u16 i_mode;
 	u16 i_nlink;
 	u16 i_uid;
 	u16 i_gid;
 	u32 i_size;
-	union { /* directories, regular files, ... */
-		unsigned char i_addb[3*(10+1+1+1)+1]; /* zone numbers: max. 10 data blocks,
-					      * then 1 indirection block,
-					      * then 1 double indirection block,
-					      * then 1 triple indirection block.
-					      * Then maybe a "file generation number" ??
-					      */
-		/* named pipes on Coherent */
-		struct {
-			char p_addp[30];
-			s16 p_pnc;
-			s16 p_prx;
-			s16 p_pwx;
-		} i_p;
-	} i_a;
+	u8  i_data[3*(10+1+1+1)];
+	u8  i_gen;
 	u32 i_atime;	/* time of last access */
 	u32 i_mtime;	/* time of last modification */
 	u32 i_ctime;	/* time of creation */
 };
 
-/* Admissible values for i_nlink: 0.._LINK_MAX */
-enum {
-	XENIX_LINK_MAX	=	126,	/* ?? */
-	SYSV_LINK_MAX	=	126,	/* 127? 251? */
-	V7_LINK_MAX     =	126,	/* ?? */
-	COH_LINK_MAX	=	10000,
-};
-
-/* The number of inodes per block is
-   sb->sv_inodes_per_block = block_size / sizeof(struct sysv_inode) */
-/* The number of indirect pointers per block is
-   sb->sv_ind_per_block = block_size / sizeof(u32) */
-
-
 /* SystemV/Coherent directory entry on disk */
-
 #define SYSV_NAMELEN	14	/* max size of name in struct sysv_dir_entry */
-
 struct sysv_dir_entry {
 	sysv_ino_t inode;
 	char name[SYSV_NAMELEN]; /* up to 14 characters, the rest are zeroes */
@@ -275,137 +198,4 @@
 
 #define SYSV_DIRSIZE	sizeof(struct sysv_dir_entry)	/* size of every directory entry */
 
-
-/* Operations */
-/* ========== */
-
-/* identify the FS in memory */
-enum {
-	FSTYPE_NONE = 0,
-	FSTYPE_XENIX,
-	FSTYPE_SYSV4,
-	FSTYPE_SYSV2,
-	FSTYPE_COH,
-	FSTYPE_V7,
-	FSTYPE_AFS,
-	FSTYPE_END,
-};
-
-#define SYSV_MAGIC_BASE		0x012FF7B3
-
-#define XENIX_SUPER_MAGIC	(SYSV_MAGIC_BASE+FSTYPE_XENIX)
-#define SYSV4_SUPER_MAGIC	(SYSV_MAGIC_BASE+FSTYPE_SYSV4)
-#define SYSV2_SUPER_MAGIC	(SYSV_MAGIC_BASE+FSTYPE_SYSV2)
-#define COH_SUPER_MAGIC		(SYSV_MAGIC_BASE+FSTYPE_COH)
-
-#ifdef __KERNEL__
-
-enum {
-	BYTESEX_LE,
-	BYTESEX_PDP,
-	BYTESEX_BE,
-};
-
-/*
- * Function prototypes
- */
-
-extern struct inode * sysv_new_inode(const struct inode *, mode_t);
-extern void sysv_free_inode(struct inode *);
-extern unsigned long sysv_count_free_inodes(struct super_block *);
-extern u32 sysv_new_block(struct super_block *);
-extern void sysv_free_block(struct super_block *, u32);
-extern unsigned long sysv_count_free_blocks(struct super_block *);
-
-extern void sysv_truncate(struct inode *);
-
-extern void sysv_write_inode(struct inode *, int);
-extern int sysv_sync_inode(struct inode *);
-extern int sysv_sync_file(struct file *, struct dentry *, int);
-extern void sysv_set_inode(struct inode *, dev_t);
-
-extern struct sysv_dir_entry *sysv_find_entry(struct dentry*, struct page**);
-extern int sysv_add_link(struct dentry*, struct inode*);
-extern int sysv_delete_entry(struct sysv_dir_entry*, struct page*);
-extern int sysv_make_empty(struct inode*, struct inode*);
-extern int sysv_empty_dir(struct inode*);
-extern void sysv_set_link(struct sysv_dir_entry*, struct page*, struct inode*);
-extern struct sysv_dir_entry *sysv_dotdot(struct inode*, struct page**);
-extern ino_t sysv_inode_by_name(struct dentry*);
-
-extern struct inode_operations sysv_file_inode_operations;
-extern struct inode_operations sysv_dir_inode_operations;
-extern struct inode_operations sysv_fast_symlink_inode_operations;
-extern struct file_operations sysv_file_operations;
-extern struct file_operations sysv_dir_operations;
-extern struct address_space_operations sysv_aops;
-extern struct super_operations sysv_sops;
-extern struct dentry_operations sysv_dentry_operations;
-
-extern struct sysv_inode *sysv_raw_inode(struct super_block *, unsigned, struct buffer_head **);
-
-static inline void dirty_sb(struct super_block *sb)
-{
-	mark_buffer_dirty(sb->sv_bh1);
-	if (sb->sv_bh1 != sb->sv_bh2)
-		mark_buffer_dirty(sb->sv_bh2);
-	sb->s_dirt = 1;
-}
-
-static inline u32 fs32_to_cpu(struct super_block *sb, u32 n)
-{
-	if (sb->sv_bytesex == BYTESEX_PDP)
-		return PDP_swab(n);
-	else if (sb->sv_bytesex == BYTESEX_LE)
-		return le32_to_cpu(n);
-	else
-		return be32_to_cpu(n);
-}
-
-static inline u32 cpu_to_fs32(struct super_block *sb, u32 n)
-{
-	if (sb->sv_bytesex == BYTESEX_PDP)
-		return PDP_swab(n);
-	else if (sb->sv_bytesex == BYTESEX_LE)
-		return cpu_to_le32(n);
-	else
-		return cpu_to_be32(n);
-}
-
-static inline u32 fs32_add(struct super_block *sb, u32 *n, int d)
-{
-	if (sb->sv_bytesex == BYTESEX_PDP)
-		return *n = PDP_swab(PDP_swab(*n)+d);
-	else if (sb->sv_bytesex == BYTESEX_LE)
-		return *n = cpu_to_le32(le32_to_cpu(*n)+d);
-	else
-		return *n = cpu_to_be32(be32_to_cpu(*n)+d);
-}
-
-static inline u16 fs16_to_cpu(struct super_block *sb, u16 n)
-{
-	if (sb->sv_bytesex != BYTESEX_BE)
-		return le16_to_cpu(n);
-	else
-		return be16_to_cpu(n);
-}
-
-static inline u16 cpu_to_fs16(struct super_block *sb, u16 n)
-{
-	if (sb->sv_bytesex != BYTESEX_BE)
-		return cpu_to_le16(n);
-	else
-		return cpu_to_be16(n);
-}
-
-static inline u16 fs16_add(struct super_block *sb, u16 *n, int d)
-{
-	if (sb->sv_bytesex != BYTESEX_BE)
-		return *n = cpu_to_le16(le16_to_cpu(*n)+d);
-	else
-		return *n = cpu_to_be16(be16_to_cpu(*n)+d);
-}
-
-#endif /* __KERNEL__ */
-
-#endif
+#endif /* _LINUX_SYSV_FS_H */
diff -Nru a/include/linux/sysv_fs_i.h b/include/linux/sysv_fs_i.h
--- a/include/linux/sysv_fs_i.h	Tue Apr 30 17:10:23 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,18 +0,0 @@
-#ifndef _SYSV_FS_I
-#define _SYSV_FS_I
-
-/*
- * SystemV/V7/Coherent FS inode data in memory
- */
-struct sysv_inode_info {
-	u32 i_data[10+1+1+1];	/* zone numbers: max. 10 data blocks,
-				 * then 1 indirection block,
-				 * then 1 double indirection block,
-				 * then 1 triple indirection block.
-				 */
-	u32 i_dir_start_lookup;
-	struct inode  vfs_inode;
-};
-
-#endif
-
diff -Nru a/include/linux/sysv_fs_sb.h b/include/linux/sysv_fs_sb.h
--- a/include/linux/sysv_fs_sb.h	Tue Apr 30 17:10:25 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,89 +0,0 @@
-#ifndef _SYSV_FS_SB
-#define _SYSV_FS_SB
-
-/*
- * SystemV/V7/Coherent super-block data in memory
- * The SystemV/V7/Coherent superblock contains dynamic data (it gets modified
- * while the system is running). This is in contrast to the Minix and Berkeley
- * filesystems (where the superblock is never modified). This affects the
- * sync() operation: we must keep the superblock in a disk buffer and use this
- * one as our "working copy".
- */
-
-struct sysv_sb_info {
-	int	       s_type;		/* file system type: FSTYPE_{XENIX|SYSV|COH} */
-	char	       s_bytesex;	/* bytesex (le/be/pdp) */
-	char	       s_truncate;	/* if 1: names > SYSV_NAMELEN chars are truncated */
-					/* if 0: they are disallowed (ENAMETOOLONG) */
-	nlink_t        s_link_max;	/* max number of hard links to a file */
-	unsigned int   s_inodes_per_block;	/* number of inodes per block */
-	unsigned int   s_inodes_per_block_1;	/* inodes_per_block - 1 */
-	unsigned int   s_inodes_per_block_bits;	/* log2(inodes_per_block) */
-	unsigned int   s_ind_per_block;		/* number of indirections per block */
-	unsigned int   s_ind_per_block_bits;	/* log2(ind_per_block) */
-	unsigned int   s_ind_per_block_2;	/* ind_per_block ^ 2 */
-	unsigned int   s_toobig_block;		/* 10 + ipb + ipb^2 + ipb^3 */
-	unsigned int   s_block_base;	/* physical block number of block 0 */
-	unsigned short s_fic_size;	/* free inode cache size, NICINOD */
-	unsigned short s_flc_size;	/* free block list chunk size, NICFREE */
-	/* The superblock is kept in one or two disk buffers: */
-	struct buffer_head *s_bh1;
-	struct buffer_head *s_bh2;
-	/* These are pointers into the disk buffer, to compensate for
-	   different superblock layout. */
-	char *         s_sbd1;		/* entire superblock data, for part 1 */
-	char *         s_sbd2;		/* entire superblock data, for part 2 */
-	u16            *s_sb_fic_count;	/* pointer to s_sbd->s_ninode */
-        u16            *s_sb_fic_inodes; /* pointer to s_sbd->s_inode */
-	u16            *s_sb_total_free_inodes; /* pointer to s_sbd->s_tinode */
-	u16            *s_bcache_count;	/* pointer to s_sbd->s_nfree */
-	u32	       *s_bcache;	/* pointer to s_sbd->s_free */
-	u32            *s_free_blocks;	/* pointer to s_sbd->s_tfree */
-	u32            *s_sb_time;	/* pointer to s_sbd->s_time */
-	u32            *s_sb_state;	/* pointer to s_sbd->s_state, only FSTYPE_SYSV */
-	/* We keep those superblock entities that don't change here;
-	   this saves us an indirection and perhaps a conversion. */
-	u32            s_firstinodezone; /* index of first inode zone */
-	u32            s_firstdatazone;	/* same as s_sbd->s_isize */
-	u32            s_ninodes;	/* total number of inodes */
-	u32            s_ndatazones;	/* total number of data zones */
-	u32            s_nzones;	/* same as s_sbd->s_fsize */
-	u16	       s_namelen;       /* max length of dir entry */
-};
-/* The field s_toobig_block is currently unused. */
-
-/* sv_ == u.sysv_sb.s_ */
-#define sv_type					u.sysv_sb.s_type
-#define sv_bytesex				u.sysv_sb.s_bytesex
-#define sv_truncate				u.sysv_sb.s_truncate
-#define sv_link_max				u.sysv_sb.s_link_max
-#define sv_inodes_per_block			u.sysv_sb.s_inodes_per_block
-#define sv_inodes_per_block_1			u.sysv_sb.s_inodes_per_block_1
-#define sv_inodes_per_block_bits		u.sysv_sb.s_inodes_per_block_bits
-#define sv_ind_per_block			u.sysv_sb.s_ind_per_block
-#define sv_ind_per_block_bits			u.sysv_sb.s_ind_per_block_bits
-#define sv_ind_per_block_2			u.sysv_sb.s_ind_per_block_2
-#define sv_toobig_block				u.sysv_sb.s_toobig_block
-#define sv_block_base				u.sysv_sb.s_block_base
-#define sv_fic_size				u.sysv_sb.s_fic_size
-#define sv_flc_size				u.sysv_sb.s_flc_size
-#define sv_bh1					u.sysv_sb.s_bh1
-#define sv_bh2					u.sysv_sb.s_bh2
-#define sv_sbd1					u.sysv_sb.s_sbd1
-#define sv_sbd2					u.sysv_sb.s_sbd2
-#define sv_sb_fic_count				u.sysv_sb.s_sb_fic_count
-#define sv_sb_fic_inodes			u.sysv_sb.s_sb_fic_inodes
-#define sv_sb_total_free_inodes			u.sysv_sb.s_sb_total_free_inodes
-#define sv_bcache_count				u.sysv_sb.s_bcache_count
-#define sv_bcache				u.sysv_sb.s_bcache
-#define sv_free_blocks				u.sysv_sb.s_free_blocks
-#define sv_sb_time				u.sysv_sb.s_sb_time
-#define sv_sb_state				u.sysv_sb.s_sb_state
-#define sv_firstinodezone			u.sysv_sb.s_firstinodezone
-#define sv_firstdatazone			u.sysv_sb.s_firstdatazone
-#define sv_ninodes				u.sysv_sb.s_ninodes
-#define sv_ndatazones				u.sysv_sb.s_ndatazones
-#define sv_nzones				u.sysv_sb.s_nzones
-#define sv_namelen                              u.sysv_sb.s_namelen
-
-#endif
diff -Nru a/include/linux/writeback.h b/include/linux/writeback.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/writeback.h	Tue Apr 30 17:10:25 2002
@@ -0,0 +1,53 @@
+/*
+ * include/linux/writeback.h.
+ *
+ * These declarations are private to fs/ and mm/.
+ * Declarations which are exported to filesystems do not
+ * get placed here.
+ */
+#ifndef WRITEBACK_H
+#define WRITEBACK_H
+
+extern spinlock_t inode_lock;
+extern struct list_head inode_in_use;
+extern struct list_head inode_unused;
+
+/*
+ * fs/fs-writeback.c
+ */
+#define WB_SYNC_NONE	0	/* Don't wait on anything */
+#define WB_SYNC_LAST	1	/* Wait on the last-written mapping */
+#define WB_SYNC_ALL	2	/* Wait on every mapping */
+
+void try_to_writeback_unused_inodes(unsigned long pexclusive);
+void writeback_single_inode(struct inode *inode,
+				int sync, int *nr_to_write);
+void writeback_unlocked_inodes(int *nr_to_write, int sync_mode,
+				unsigned long *older_than_this);
+void writeback_inodes_sb(struct super_block *);
+void __wait_on_inode(struct inode * inode);
+void sync_inodes(void);
+
+static inline void wait_on_inode(struct inode *inode)
+{
+	if (inode->i_state & I_LOCK)
+		__wait_on_inode(inode);
+}
+
+/*
+ * mm/page-writeback.c
+ */
+/*
+ * How much data to write out at a time in various places.  This isn't
+ * really very important - it's just here to prevent any thread from
+ * locking an inode for too long and blocking other threads which wish
+ * to write the same file for allocation throttling purposes.
+ */
+#define WRITEOUT_PAGES	((4096 * 1024) / PAGE_CACHE_SIZE)
+
+void balance_dirty_pages(struct address_space *mapping);
+void balance_dirty_pages_ratelimited(struct address_space *mapping);
+int pdflush_flush(unsigned long nr_pages);
+int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0);
+
+#endif		/* WRITEBACK_H */
diff -Nru a/include/net/profile.h b/include/net/profile.h
--- a/include/net/profile.h	Tue Apr 30 17:10:23 2002
+++ b/include/net/profile.h	Tue Apr 30 17:10:23 2002
@@ -44,7 +44,7 @@
 			      "sbbl %3,%1\n\t" 
 			      "addl %4,%0\n\t" 
 			      "adcl %5,%1\n\t" 
-			      "subl " SYMBOL_NAME_STR(net_profile_adjust) "+4,%0\n\t" 
+			      "subl net_profile_adjust+4,%0\n\t" 
 			      "sbbl $0,%1\n\t" 
 			      : "=r" (acc->tv_usec), "=r" (acc->tv_sec)
 			      : "g" (entered->tv_usec), "g" (entered->tv_sec),
diff -Nru a/include/sound/asound.h b/include/sound/asound.h
--- a/include/sound/asound.h	Tue Apr 30 17:10:25 2002
+++ b/include/sound/asound.h	Tue Apr 30 17:10:25 2002
@@ -30,6 +30,7 @@
 #ifdef __KERNEL__
 
 #include <linux/types.h>
+#include <linux/time.h>
 #include <asm/byteorder.h>
 
 #if  __LITTLE_ENDIAN == 1234
diff -Nru a/include/sound/core.h b/include/sound/core.h
--- a/include/sound/core.h	Tue Apr 30 17:10:25 2002
+++ b/include/sound/core.h	Tue Apr 30 17:10:25 2002
@@ -314,11 +314,11 @@
 /* --- */
 
 #ifdef CONFIG_SND_VERBOSE_PRINTK
-#define snd_printk(args...) \
-	snd_verbose_printk(__FILE__, __LINE__, ##args)
+#define snd_printk(fmt, args...) \
+	snd_verbose_printk(__FILE__, __LINE__, fmt ,##args)
 #else
-#define snd_printk(args...) \
-	printk(##args)
+#define snd_printk(fmt, args...) \
+	printk(fmt ,##args)
 #endif
 
 #ifdef CONFIG_SND_DEBUG
@@ -326,8 +326,8 @@
 #define __ASTRING__(x) #x
 
 #ifdef CONFIG_SND_VERBOSE_PRINTK
-#define snd_printd(args...) \
-	snd_verbose_printd(__FILE__, __LINE__, ##args)
+#define snd_printd(fmt, args...) \
+	snd_verbose_printd(__FILE__, __LINE__, fmt ,##args)
 #endif
 #define snd_assert(expr, args...) do {\
 	if (!(expr)) {\
@@ -344,16 +344,16 @@
 
 #else /* !CONFIG_SND_DEBUG */
 
-#define snd_printd(args...)	/* nothing */
-#define snd_assert(args...)	/* nothing */
+#define snd_printd(fmt, args...)	/* nothing */
+#define snd_assert(expr, args...)	/* nothing */
 #define snd_runtime_check(expr, args...) do { if (!(expr)) { args; } } while (0)
 
 #endif /* CONFIG_SND_DEBUG */
 
 #ifdef CONFIG_SND_DEBUG_DETECT
-#define snd_printdd(args...) snd_printk(format, ##args)
+#define snd_printdd(format, args...) snd_printk(format, ##args)
 #else
-#define snd_printdd(args...) /* nothing */
+#define snd_printdd(format, args...) /* nothing */
 #endif
 
 #define snd_BUG() snd_assert(0, )
diff -Nru a/include/sound/version.h b/include/sound/version.h
--- a/include/sound/version.h	Tue Apr 30 17:10:25 2002
+++ b/include/sound/version.h	Tue Apr 30 17:10:25 2002
@@ -1,3 +1,3 @@
 /* include/version.h.  Generated automatically by configure.  */
 #define CONFIG_SND_VERSION "0.9.0rc1"
-#define CONFIG_SND_DATE " (Sun Apr 28 20:04:42 2002 UTC)"
+#define CONFIG_SND_DATE " (Mon Apr 29 06:46:09 2002 UTC)"
diff -Nru a/init/main.c b/init/main.c
--- a/init/main.c	Tue Apr 30 17:10:24 2002
+++ b/init/main.c	Tue Apr 30 17:10:24 2002
@@ -389,8 +389,8 @@
 
 	fork_init(mempages);
 	proc_caches_init();
+	buffer_init();
 	vfs_caches_init(mempages);
-	buffer_init(mempages);
 	radix_tree_init();
 #if defined(CONFIG_ARCH_S390)
 	ccwcache_init();
diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c
--- a/kernel/ksyms.c	Tue Apr 30 17:10:23 2002
+++ b/kernel/ksyms.c	Tue Apr 30 17:10:23 2002
@@ -168,8 +168,6 @@
 EXPORT_SYMBOL(__d_path);
 EXPORT_SYMBOL(mark_buffer_dirty);
 EXPORT_SYMBOL(end_buffer_io_sync);
-EXPORT_SYMBOL(set_buffer_async_io);
-EXPORT_SYMBOL(__mark_buffer_dirty);
 EXPORT_SYMBOL(__mark_inode_dirty);
 EXPORT_SYMBOL(get_empty_filp);
 EXPORT_SYMBOL(init_private_file);
@@ -186,7 +184,6 @@
 EXPORT_SYMBOL(truncate_inode_pages);
 EXPORT_SYMBOL(fsync_dev);
 EXPORT_SYMBOL(fsync_bdev);
-EXPORT_SYMBOL(fsync_no_super);
 EXPORT_SYMBOL(permission);
 EXPORT_SYMBOL(vfs_permission);
 EXPORT_SYMBOL(inode_setattr);
@@ -210,9 +207,7 @@
 EXPORT_SYMBOL(submit_bh);
 EXPORT_SYMBOL(unlock_buffer);
 EXPORT_SYMBOL(__wait_on_buffer);
-EXPORT_SYMBOL(___wait_on_page);
 EXPORT_SYMBOL(generic_direct_IO);
-EXPORT_SYMBOL(discard_bh_page);
 EXPORT_SYMBOL(block_write_full_page);
 EXPORT_SYMBOL(block_read_full_page);
 EXPORT_SYMBOL(block_prepare_write);
@@ -227,7 +222,6 @@
 EXPORT_SYMBOL(generic_file_write);
 EXPORT_SYMBOL(generic_file_mmap);
 EXPORT_SYMBOL(generic_ro_fops);
-EXPORT_SYMBOL(generic_buffer_fdatasync);
 EXPORT_SYMBOL(file_lock_list);
 EXPORT_SYMBOL(locks_init_lock);
 EXPORT_SYMBOL(locks_copy_lock);
@@ -308,7 +302,7 @@
 EXPORT_SYMBOL(dentry_open);
 EXPORT_SYMBOL(filemap_nopage);
 EXPORT_SYMBOL(filemap_sync);
-EXPORT_SYMBOL(filemap_fdatasync);
+EXPORT_SYMBOL(filemap_fdatawrite);
 EXPORT_SYMBOL(filemap_fdatawait);
 EXPORT_SYMBOL(lock_page);
 EXPORT_SYMBOL(unlock_page);
@@ -339,7 +333,6 @@
 EXPORT_SYMBOL(read_dev_sector);
 EXPORT_SYMBOL(tq_disk);
 EXPORT_SYMBOL(init_buffer);
-EXPORT_SYMBOL(refile_buffer);
 EXPORT_SYMBOL(wipe_partitions);
 
 /* tty routines */
diff -Nru a/kernel/sched.c b/kernel/sched.c
--- a/kernel/sched.c	Tue Apr 30 17:10:25 2002
+++ b/kernel/sched.c	Tue Apr 30 17:10:25 2002
@@ -28,8 +28,13 @@
  * priority range is allocated to RT tasks, the 100-139
  * range is for SCHED_OTHER tasks. Priority values are
  * inverted: lower p->prio value means higher priority.
+ * 
+ * MAX_USER_RT_PRIO allows the actual maximum RT priority
+ * to be separate from the value exported to user-space.
+ * NOTE: MAX_RT_PRIO must not be smaller than MAX_USER_RT_PRIO.
  */
 #define MAX_RT_PRIO		100
+#define MAX_USER_RT_PRIO	100
 #define MAX_PRIO		(MAX_RT_PRIO + 40)
 
 /*
@@ -1071,7 +1076,7 @@
  */
 int task_prio(task_t *p)
 {
-	return p->prio - 100;
+	return p->prio - MAX_USER_RT_PRIO;
 }
 
 int task_nice(task_t *p)
@@ -1137,7 +1142,7 @@
 	 * priority for SCHED_OTHER is 0.
 	 */
 	retval = -EINVAL;
-	if (lp.sched_priority < 0 || lp.sched_priority > 99)
+	if (lp.sched_priority < 0 || lp.sched_priority > MAX_USER_RT_PRIO-1)
 		goto out_unlock;
 	if ((policy == SCHED_OTHER) != (lp.sched_priority == 0))
 		goto out_unlock;
@@ -1157,7 +1162,7 @@
 	p->policy = policy;
 	p->rt_priority = lp.sched_priority;
 	if (policy != SCHED_OTHER)
-		p->prio = 99 - p->rt_priority;
+		p->prio = MAX_USER_RT_PRIO-1 - p->rt_priority;
 	else
 		p->prio = p->static_prio;
 	if (array)
@@ -1237,7 +1242,7 @@
 /**
  * sys_sched_setaffinity - set the cpu affinity of a process
  * @pid: pid of the process
- * @len: length of the bitmask pointed to by user_mask_ptr
+ * @len: length in bytes of the bitmask pointed to by user_mask_ptr
  * @user_mask_ptr: user-space pointer to the new cpu mask
  */
 asmlinkage int sys_sched_setaffinity(pid_t pid, unsigned int len,
@@ -1289,7 +1294,7 @@
 /**
  * sys_sched_getaffinity - get the cpu affinity of a process
  * @pid: pid of the process
- * @len: length of the bitmask pointed to by user_mask_ptr
+ * @len: length in bytes of the bitmask pointed to by user_mask_ptr
  * @user_mask_ptr: user-space pointer to hold the current cpu mask
  */
 asmlinkage int sys_sched_getaffinity(pid_t pid, unsigned int len,
@@ -1371,7 +1376,7 @@
 	switch (policy) {
 	case SCHED_FIFO:
 	case SCHED_RR:
-		ret = 99;
+		ret = MAX_USER_RT_PRIO-1;
 		break;
 	case SCHED_OTHER:
 		ret = 0;
@@ -1511,6 +1516,12 @@
 	read_unlock(&tasklist_lock);
 }
 
+/*
+ * double_rq_lock - safely lock two runqueues
+ *
+ * Note this does not disable interrupts like task_rq_lock,
+ * you need to do so manually before calling.
+ */
 static inline void double_rq_lock(runqueue_t *rq1, runqueue_t *rq2)
 {
 	if (rq1 == rq2)
@@ -1526,6 +1537,12 @@
 	}
 }
 
+/*
+ * double_rq_unlock - safely unlock two runqueues
+ *
+ * Note this does not restore interrupts like task_rq_unlock,
+ * you need to do so manually after calling.
+ */
 static inline void double_rq_unlock(runqueue_t *rq1, runqueue_t *rq2)
 {
 	spin_unlock(&rq1->lock);
@@ -1675,7 +1692,7 @@
 static int migration_thread(void * bind_cpu)
 {
 	int cpu = cpu_logical_map((int) (long) bind_cpu);
-	struct sched_param param = { sched_priority: 99 };
+	struct sched_param param = { sched_priority: MAX_RT_PRIO-1 };
 	runqueue_t *rq;
 	int ret;
 
diff -Nru a/kernel/sysctl.c b/kernel/sysctl.c
--- a/kernel/sysctl.c	Tue Apr 30 17:10:23 2002
+++ b/kernel/sysctl.c	Tue Apr 30 17:10:23 2002
@@ -43,7 +43,6 @@
 /* External variables not in a header file. */
 extern int panic_timeout;
 extern int C_A_D;
-extern int bdf_prm[], bdflush_min[], bdflush_max[];
 extern int sysctl_overcommit_memory;
 extern int max_threads;
 extern atomic_t nr_queued_signals;
@@ -259,9 +258,6 @@
 };
 
 static ctl_table vm_table[] = {
-	{VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0644, NULL,
-	 &proc_dointvec_minmax, &sysctl_intvec, NULL,
-	 &bdflush_min, &bdflush_max},
 	{VM_OVERCOMMIT_MEMORY, "overcommit_memory", &sysctl_overcommit_memory,
 	 sizeof(sysctl_overcommit_memory), 0644, NULL, &proc_dointvec},
 	{VM_PAGERDAEMON, "kswapd",
diff -Nru a/mm/Makefile b/mm/Makefile
--- a/mm/Makefile	Tue Apr 30 17:10:25 2002
+++ b/mm/Makefile	Tue Apr 30 17:10:25 2002
@@ -9,12 +9,13 @@
 
 O_TARGET := mm.o
 
-export-objs := shmem.o filemap.o mempool.o page_alloc.o
+export-objs := shmem.o filemap.o mempool.o page_alloc.o \
+		page-writeback.o
 
 obj-y	 := memory.o mmap.o filemap.o mprotect.o mlock.o mremap.o \
 	    vmalloc.o slab.o bootmem.o swap.o vmscan.o page_io.o \
 	    page_alloc.o swap_state.o swapfile.o numa.o oom_kill.o \
 	    shmem.o highmem.o mempool.o msync.o mincore.o readahead.o \
-	    pdflush.o
+	    pdflush.o page-writeback.o
 
 include $(TOPDIR)/Rules.make
diff -Nru a/mm/filemap.c b/mm/filemap.c
--- a/mm/filemap.c	Tue Apr 30 17:10:25 2002
+++ b/mm/filemap.c	Tue Apr 30 17:10:25 2002
@@ -11,29 +11,19 @@
  */
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/shm.h>
+#include <linux/compiler.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
 #include <linux/mman.h>
-#include <linux/locks.h>
 #include <linux/pagemap.h>
-#include <linux/swap.h>
-#include <linux/smp_lock.h>
-#include <linux/blkdev.h>
 #include <linux/file.h>
-#include <linux/swapctl.h>
-#include <linux/init.h>
-#include <linux/mm.h>
 #include <linux/iobuf.h>
-#include <linux/compiler.h>
-#include <linux/fs.h>
 #include <linux/hash.h>
-#include <linux/blkdev.h>
+#include <linux/writeback.h>
 
-#include <asm/pgalloc.h>
 #include <asm/uaccess.h>
 #include <asm/mman.h>
 
-#include <linux/highmem.h>
-
 /*
  * Shared mappings implemented 30.11.1994. It's not fully working yet,
  * though.
@@ -46,17 +36,20 @@
  * SMP-threaded pagemap-LRU 1999, Andrea Arcangeli <andrea@suse.de>
  */
 
-atomic_t page_cache_size = ATOMIC_INIT(0);
 
 /*
  * Lock ordering:
- *	pagemap_lru_lock ==> page_lock ==> i_shared_lock
+ *
+ *  pagemap_lru_lock
+ *  ->i_shared_lock		(vmtruncate)
+ *    ->i_bufferlist_lock	(__free_pte->__set_page_dirty_buffers)
+ *      ->unused_list_lock	(try_to_free_buffers)
+ *        ->mapping->page_lock
+ *      ->inode_lock		(__mark_inode_dirty)
+ *        ->sb_lock		(fs/fs-writeback.c)
  */
 spinlock_t pagemap_lru_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
-#define CLUSTER_PAGES		(1 << page_cluster)
-#define CLUSTER_OFFSET(x)	(((x) >> page_cluster) << page_cluster)
-
 /*
  * Remove a page from the page cache and free it. Caller has to make
  * sure the page is locked and that nobody else uses it - or that usage
@@ -74,7 +67,7 @@
 	page->mapping = NULL;
 
 	mapping->nrpages--;
-	atomic_dec(&page_cache_size);
+	dec_page_state(nr_pagecache);
 }
 
 void remove_inode_page(struct page *page)
@@ -98,26 +91,6 @@
 	return 0;
 }
 
-/*
- * Add a page to the dirty page list.
- */
-void set_page_dirty(struct page *page)
-{
-	if (!test_and_set_bit(PG_dirty, &page->flags)) {
-		struct address_space *mapping = page->mapping;
-
-		if (mapping) {
-			write_lock(&mapping->page_lock);
-			list_del(&page->list);
-			list_add(&page->list, &mapping->dirty_pages);
-			write_unlock(&mapping->page_lock);
-
-			if (mapping->host)
-				mark_inode_dirty_pages(mapping->host);
-		}
-	}
-}
-
 /**
  * invalidate_inode_pages - Invalidate all the unlocked pages of one inode
  * @inode: the inode which pages we want to invalidate
@@ -147,7 +120,7 @@
 			continue;
 
 		/* ..or locked */
-		if (TryLockPage(page))
+		if (TestSetPageLocked(page))
 			continue;
 
 		if (PagePrivate(page) && !try_to_release_page(page, 0))
@@ -158,11 +131,11 @@
 
 		__lru_cache_del(page);
 		__remove_inode_page(page);
-		UnlockPage(page);
+		unlock_page(page);
 		page_cache_release(page);
 		continue;
 unlock:
-		UnlockPage(page);
+		unlock_page(page);
 		continue;
 	}
 
@@ -195,20 +168,19 @@
 	/* Leave it on the LRU if it gets converted into anonymous buffers */
 	if (!PagePrivate(page) || do_flushpage(page, 0))
 		lru_cache_del(page);
-
-	/*
-	 * We remove the page from the page cache _after_ we have
-	 * destroyed all buffer-cache references to it. Otherwise some
-	 * other process might think this inode page is not in the
-	 * page cache and creates a buffer-cache alias to it causing
-	 * all sorts of fun problems ...  
-	 */
 	ClearPageDirty(page);
 	ClearPageUptodate(page);
 	remove_inode_page(page);
 	page_cache_release(page);
 }
 
+/*
+ * Writeback walks the page list in ->prev order, which is low-to-high file
+ * offsets in the common case where he file was written linearly. So truncate
+ * walks the page list in the opposite (->next) direction, to avoid getting
+ * into lockstep with writeback's cursor.  To prune as many pages as possible
+ * before the truncate cursor collides with the writeback cursor.
+ */
 static int truncate_list_pages(struct address_space *mapping,
 	struct list_head *head, unsigned long start, unsigned *partial)
 {
@@ -217,7 +189,7 @@
 	int unlocked = 0;
 
  restart:
-	curr = head->prev;
+	curr = head->next;
 	while (curr != head) {
 		unsigned long offset;
 
@@ -229,15 +201,26 @@
 			int failed;
 
 			page_cache_get(page);
-			failed = TryLockPage(page);
+			if (PageWriteback(page)) {
+				/*
+				 * urgggh. This function is utterly foul,
+				 * and this addition doesn't help.  Kill.
+				 */
+				write_unlock(&mapping->page_lock);
+				wait_on_page_writeback(page);
+				unlocked = 1;
+				write_lock(&mapping->page_lock);
+				goto restart;
+			}
+			failed = TestSetPageLocked(page);
 
 			list_del(head);
 			if (!failed)
 				/* Restart after this page */
-				list_add_tail(head, curr);
+				list_add(head, curr);
 			else
 				/* Restart on this page */
-				list_add(head, curr);
+				list_add_tail(head, curr);
 
 			write_unlock(&mapping->page_lock);
 			unlocked = 1;
@@ -249,9 +232,9 @@
 				} else 
 					truncate_complete_page(page);
 
-				UnlockPage(page);
+				unlock_page(page);
 			} else
- 				wait_on_page(page);
+ 				wait_on_page_locked(page);
 
 			page_cache_release(page);
 
@@ -263,11 +246,28 @@
 			write_lock(&mapping->page_lock);
 			goto restart;
 		}
-		curr = curr->prev;
+		curr = curr->next;
 	}
 	return unlocked;
 }
 
+/*
+ * Unconditionally clean all pages outside `start'.  The mapping lock
+ * must be held.
+ */
+static void clean_list_pages(struct address_space *mapping,
+		struct list_head *head, unsigned long start)
+{
+	struct page *page;
+	struct list_head *curr;
+
+	for (curr = head->next; curr != head; curr = curr->next) {
+		page = list_entry(curr, struct page, list);
+		if (page->index > start)
+			ClearPageDirty(page);
+	}
+}
+
 /**
  * truncate_inode_pages - truncate *all* the pages from an offset
  * @mapping: mapping to truncate
@@ -284,11 +284,15 @@
 	int unlocked;
 
 	write_lock(&mapping->page_lock);
+	clean_list_pages(mapping, &mapping->io_pages, start);
+	clean_list_pages(mapping, &mapping->dirty_pages, start);
 	do {
-		unlocked = truncate_list_pages(mapping,
-				&mapping->clean_pages, start, &partial);
+		unlocked |= truncate_list_pages(mapping,
+				&mapping->io_pages, start, &partial);
 		unlocked |= truncate_list_pages(mapping,
 				&mapping->dirty_pages, start, &partial);
+		unlocked = truncate_list_pages(mapping,
+				&mapping->clean_pages, start, &partial);
 		unlocked |= truncate_list_pages(mapping,
 				&mapping->locked_pages, start, &partial);
 	} while (unlocked);
@@ -306,6 +310,7 @@
 	/*
 	 * The page is locked and we hold the mapping lock as well
 	 * so both page_count(page) and page_buffers stays constant here.
+	 * AKPM: fixme: No global lock any more.  Is this still OK?
 	 */
 	if (page_count(page) == 1 + !!page_has_buffers(page)) {
 		/* Restart after this page */
@@ -323,7 +328,7 @@
 
 			page_cache_get(page);
 			write_unlock(&mapping->page_lock);
-			block_invalidate_page(page);
+			block_flushpage(page, 0);
 		} else
 			unlocked = 0;
 
@@ -346,11 +351,18 @@
 	while (curr != head) {
 		page = list_entry(curr, struct page, list);
 
-		if (!TryLockPage(page)) {
+		if (PageWriteback(page)) {
+			write_unlock(&mapping->page_lock);
+			wait_on_page_writeback(page);
+			unlocked = 1;
+			write_lock(&mapping->page_lock);
+			goto restart;
+		}
+		if (!TestSetPageLocked(page)) {
 			int __unlocked;
 
 			__unlocked = invalidate_this_page2(mapping, page, curr, head);
-			UnlockPage(page);
+			unlock_page(page);
 			unlocked |= __unlocked;
 			if (!__unlocked) {
 				curr = curr->prev;
@@ -364,7 +376,7 @@
 			page_cache_get(page);
 			write_unlock(&mapping->page_lock);
 			unlocked = 1;
-			wait_on_page(page);
+			wait_on_page_locked(page);
 		}
 
 		page_cache_release(page);
@@ -395,77 +407,13 @@
 		unlocked |= invalidate_list_pages2(mapping,
 				&mapping->dirty_pages);
 		unlocked |= invalidate_list_pages2(mapping,
+				&mapping->io_pages);
+		unlocked |= invalidate_list_pages2(mapping,
 				&mapping->locked_pages);
 	} while (unlocked);
 	write_unlock(&mapping->page_lock);
 }
 
-static int do_buffer_fdatasync(struct address_space *mapping,
-		struct list_head *head, unsigned long start,
-		unsigned long end, int (*fn)(struct page *))
-{
-	struct list_head *curr;
-	struct page *page;
-	int retval = 0;
-
-	write_lock(&mapping->page_lock);
-	curr = head->next;
-	while (curr != head) {
-		page = list_entry(curr, struct page, list);
-		curr = curr->next;
-		if (!page_has_buffers(page))
-			continue;
-		if (page->index >= end)
-			continue;
-		if (page->index < start)
-			continue;
-
-		page_cache_get(page);
-		write_unlock(&mapping->page_lock);
-		lock_page(page);
-
-		/* The buffers could have been free'd while we waited for the page lock */
-		if (page_has_buffers(page))
-			retval |= fn(page);
-
-		UnlockPage(page);
-		write_lock(&mapping->page_lock);
-		curr = page->list.next;
-		page_cache_release(page);
-	}
-	write_unlock(&mapping->page_lock);
-
-	return retval;
-}
-
-/*
- * Two-stage data sync: first start the IO, then go back and
- * collect the information..
- */
-int generic_buffer_fdatasync(struct inode *inode, unsigned long start_idx, unsigned long end_idx)
-{
-	struct address_space *mapping = inode->i_mapping;
-	int retval;
-
-	/* writeout dirty buffers on pages from both clean and dirty lists */
-	retval = do_buffer_fdatasync(mapping, &mapping->dirty_pages,
-			start_idx, end_idx, writeout_one_page);
-	retval |= do_buffer_fdatasync(mapping, &mapping->clean_pages,
-			start_idx, end_idx, writeout_one_page);
-	retval |= do_buffer_fdatasync(mapping, &mapping->locked_pages,
-			start_idx, end_idx, writeout_one_page);
-
-	/* now wait for locked buffers on pages from both clean and dirty lists */
-	retval |= do_buffer_fdatasync(mapping, &mapping->dirty_pages,
-			start_idx, end_idx, waitfor_one_page);
-	retval |= do_buffer_fdatasync(mapping, &mapping->clean_pages,
-			start_idx, end_idx, waitfor_one_page);
-	retval |= do_buffer_fdatasync(mapping, &mapping->locked_pages,
-			start_idx, end_idx, waitfor_one_page);
-
-	return retval;
-}
-
 /*
  * In-memory filesystems have to fail their
  * writepage function - and this has to be
@@ -489,54 +437,23 @@
 
 	/* Set the page dirty again, unlock */
 	SetPageDirty(page);
-	UnlockPage(page);
+	unlock_page(page);
 	return 0;
 }
-
 EXPORT_SYMBOL(fail_writepage);
 
 /**
- *      filemap_fdatasync - walk the list of dirty pages of the given address space
- *     	and writepage() all of them.
- * 
- *      @mapping: address space structure to write
+ *  filemap_fdatawrite - walk the list of dirty pages of the given address space
+ *                      and writepage() all of them.
+ *
+ *  @mapping: address space structure to write
  *
  */
-int filemap_fdatasync(struct address_space * mapping)
+int filemap_fdatawrite(struct address_space *mapping)
 {
-	int ret = 0;
-	int (*writepage)(struct page *) = mapping->a_ops->writepage;
-
-	write_lock(&mapping->page_lock);
-
-        while (!list_empty(&mapping->dirty_pages)) {
-		struct page *page = list_entry(mapping->dirty_pages.prev, struct page, list);
-
-		list_del(&page->list);
-		list_add(&page->list, &mapping->locked_pages);
-
-		if (!PageDirty(page))
-			continue;
-
-		page_cache_get(page);
-		write_unlock(&mapping->page_lock);
-
-		lock_page(page);
-
-		if (PageDirty(page)) {
-			int err;
-			ClearPageDirty(page);
-			err = writepage(page);
-			if (err && !ret)
-				ret = err;
-		} else
-			UnlockPage(page);
-
-		page_cache_release(page);
-		write_lock(&mapping->page_lock);
-	}
-	write_unlock(&mapping->page_lock);
-	return ret;
+	if (mapping->a_ops->writeback_mapping)
+		return mapping->a_ops->writeback_mapping(mapping, NULL);
+	return generic_writeback_mapping(mapping, NULL);
 }
 
 /**
@@ -556,15 +473,18 @@
 		struct page *page = list_entry(mapping->locked_pages.next, struct page, list);
 
 		list_del(&page->list);
-		list_add(&page->list, &mapping->clean_pages);
+		if (PageDirty(page))
+			list_add(&page->list, &mapping->dirty_pages);
+		else
+			list_add(&page->list, &mapping->clean_pages);
 
-		if (!PageLocked(page))
+		if (!PageWriteback(page))
 			continue;
 
 		page_cache_get(page);
 		write_unlock(&mapping->page_lock);
 
-		___wait_on_page(page);
+		wait_on_page_writeback(page);
 		if (PageError(page))
 			ret = -EIO;
 
@@ -583,13 +503,13 @@
 static int __add_to_page_cache(struct page *page,
 		struct address_space *mapping, unsigned long offset)
 {
-	unsigned long flags;
-
 	page_cache_get(page);
 	if (radix_tree_insert(&mapping->page_tree, offset, page) < 0)
 		goto nomem;
-	flags = page->flags & ~(1 << PG_uptodate | 1 << PG_error | 1 << PG_dirty | 1 << PG_referenced | 1 << PG_arch_1 | 1 << PG_checked);
-	page->flags = flags | (1 << PG_locked);
+	page->flags &= ~(1 << PG_uptodate | 1 << PG_error |
+			1 << PG_referenced | 1 << PG_arch_1 | 1 << PG_checked);
+	SetPageLocked(page);
+	ClearPageDirty(page);
 	___add_to_page_cache(page, mapping, offset);
 	return 0;
  nomem:
@@ -681,14 +601,7 @@
 	return &zone->wait_table[hash_ptr(page, zone->wait_table_bits)];
 }
 
-/* 
- * Wait for a page to get unlocked.
- *
- * This must be called with the caller "holding" the page,
- * ie with increased "page->count" so that the page won't
- * go away during the wait..
- */
-void ___wait_on_page(struct page *page)
+static void wait_on_page_bit(struct page *page, int bit_nr)
 {
 	wait_queue_head_t *waitqueue = page_waitqueue(page);
 	struct task_struct *tsk = current;
@@ -697,29 +610,79 @@
 	add_wait_queue(waitqueue, &wait);
 	do {
 		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-		if (!PageLocked(page))
+		if (!test_bit(bit_nr, &page->flags))
 			break;
 		sync_page(page);
 		schedule();
-	} while (PageLocked(page));
+	} while (test_bit(bit_nr, &page->flags));
 	__set_task_state(tsk, TASK_RUNNING);
 	remove_wait_queue(waitqueue, &wait);
 }
 
-/*
- * Unlock the page and wake up sleepers in ___wait_on_page.
+/* 
+ * Wait for a page to be unlocked.
+ *
+ * This must be called with the caller "holding" the page,
+ * ie with increased "page->count" so that the page won't
+ * go away during the wait..
+ */
+void ___wait_on_page_locked(struct page *page)
+{
+	wait_on_page_bit(page, PG_locked_dontuse);
+}
+EXPORT_SYMBOL(___wait_on_page_locked);
+
+/* 
+ * Wait for a page to complete writeback
+ */
+void wait_on_page_writeback(struct page *page)
+{
+	wait_on_page_bit(page, PG_writeback);
+}
+EXPORT_SYMBOL(wait_on_page_writeback);
+
+/**
+ * unlock_page() - unlock a locked page
+ *
+ * @page: the page
+ *
+ * Unlocks the page and wakes up sleepers in ___wait_on_page_locked().
+ * Also wakes sleepers in wait_on_page_writeback() because the wakeup
+ * mechananism between PageLocked pages and PageWriteback pages is shared.
+ * But that's OK - sleepers in wait_on_page_writeback() just go back to sleep.
+ *
+ * The first mb is necessary to safely close the critical section opened by the
+ * TryLockPage(), the second mb is necessary to enforce ordering between
+ * the clear_bit and the read of the waitqueue (to avoid SMP races with a
+ * parallel wait_on_page_locked()).
  */
 void unlock_page(struct page *page)
 {
 	wait_queue_head_t *waitqueue = page_waitqueue(page);
 	clear_bit(PG_launder, &(page)->flags);
 	smp_mb__before_clear_bit();
-	if (!test_and_clear_bit(PG_locked, &(page)->flags))
+	if (!TestClearPageLocked(page))
+		BUG();
+	smp_mb__after_clear_bit(); 
+	if (waitqueue_active(waitqueue))
+		wake_up_all(waitqueue);
+}
+
+/*
+ * End writeback against a page.
+ */
+void end_page_writeback(struct page *page)
+{
+	wait_queue_head_t *waitqueue = page_waitqueue(page);
+	clear_bit(PG_launder, &(page)->flags);
+	smp_mb__before_clear_bit();
+	if (!TestClearPageWriteback(page))
 		BUG();
 	smp_mb__after_clear_bit(); 
 	if (waitqueue_active(waitqueue))
 		wake_up_all(waitqueue);
 }
+EXPORT_SYMBOL(end_page_writeback);
 
 /*
  * Get a lock on the page, assuming we need to sleep
@@ -738,7 +701,7 @@
 			sync_page(page);
 			schedule();
 		}
-		if (!TryLockPage(page))
+		if (!TestSetPageLocked(page))
 			break;
 	}
 	__set_task_state(tsk, TASK_RUNNING);
@@ -757,7 +720,7 @@
  */
 void lock_page(struct page *page)
 {
-	if (TryLockPage(page))
+	if (TestSetPageLocked(page))
 		__lock_page(page);
 }
 
@@ -790,7 +753,7 @@
 
 	read_lock(&mapping->page_lock);
 	page = radix_tree_lookup(&mapping->page_tree, offset);
-	if (page && TryLockPage(page))
+	if (page && TestSetPageLocked(page))
 		page = NULL;
 	read_unlock(&mapping->page_lock);
 	return page;
@@ -814,14 +777,14 @@
 	page = radix_tree_lookup(&mapping->page_tree, offset);
 	if (page) {
 		page_cache_get(page);
-		if (TryLockPage(page)) {
+		if (TestSetPageLocked(page)) {
 			write_unlock(&mapping->page_lock);
 			lock_page(page);
 			write_lock(&mapping->page_lock);
 
 			/* Has the page been truncated while we slept? */
 			if (page->mapping != mapping || page->index != offset) {
-				UnlockPage(page);
+				unlock_page(page);
 				page_cache_release(page);
 				goto repeat;
 			}
@@ -930,12 +893,12 @@
 	page = find_get_page(mapping, index);
 
 	if ( page ) {
-		if ( !TryLockPage(page) ) {
+		if ( !TestSetPageLocked(page) ) {
 			/* Page found and locked */
 			/* This test is overly paranoid, but what the heck... */
 			if ( unlikely(page->mapping != mapping || page->index != index) ) {
 				/* Someone reallocated this page under us. */
-				UnlockPage(page);
+				unlock_page(page);
 				page_cache_release(page);
 				return NULL;
 			} else {
@@ -1039,7 +1002,7 @@
 		page_cache_get(page);
 		write_unlock(&mapping->page_lock);
 
-		if (!Page_Uptodate(page))
+		if (!PageUptodate(page))
 			goto page_not_up_to_date;
 page_ok:
 		/* If users can be writing to this page using arbitrary
@@ -1076,7 +1039,7 @@
 		break;
 
 page_not_up_to_date:
-		if (Page_Uptodate(page))
+		if (PageUptodate(page))
 			goto page_ok;
 
 		/* Get exclusive access to the page ... */
@@ -1084,14 +1047,14 @@
 
 		/* Did it get unhashed before we got the lock? */
 		if (!page->mapping) {
-			UnlockPage(page);
+			unlock_page(page);
 			page_cache_release(page);
 			continue;
 		}
 
 		/* Did somebody else fill it already? */
-		if (Page_Uptodate(page)) {
-			UnlockPage(page);
+		if (PageUptodate(page)) {
+			unlock_page(page);
 			goto page_ok;
 		}
 
@@ -1100,10 +1063,10 @@
 		error = mapping->a_ops->readpage(filp, page);
 
 		if (!error) {
-			if (Page_Uptodate(page))
+			if (PageUptodate(page))
 				goto page_ok;
-			wait_on_page(page);
-			if (Page_Uptodate(page))
+			wait_on_page_locked(page);
+			if (PageUptodate(page))
 				goto page_ok;
 			error = -EIO;
 		}
@@ -1196,9 +1159,9 @@
 	 * Flush to disk exclusively the _data_, metadata must remain
 	 * completly asynchronous or performance will go to /dev/null.
 	 */
-	retval = filemap_fdatasync(mapping);
+	retval = filemap_fdatawait(mapping);
 	if (retval == 0)
-		retval = fsync_inode_data_buffers(inode);
+		retval = filemap_fdatawrite(mapping);
 	if (retval == 0)
 		retval = filemap_fdatawait(mapping);
 	if (retval < 0)
@@ -1567,7 +1530,7 @@
 	 * Ok, found a page in the page cache, now we need to check
 	 * that it's up-to-date.
 	 */
-	if (!Page_Uptodate(page))
+	if (!PageUptodate(page))
 		goto page_not_uptodate;
 
 success:
@@ -1608,20 +1571,20 @@
 
 	/* Did it get unhashed while we waited for it? */
 	if (!page->mapping) {
-		UnlockPage(page);
+		unlock_page(page);
 		page_cache_release(page);
 		goto retry_all;
 	}
 
 	/* Did somebody else get it up-to-date? */
-	if (Page_Uptodate(page)) {
-		UnlockPage(page);
+	if (PageUptodate(page)) {
+		unlock_page(page);
 		goto success;
 	}
 
 	if (!mapping->a_ops->readpage(file, page)) {
-		wait_on_page(page);
-		if (Page_Uptodate(page))
+		wait_on_page_locked(page);
+		if (PageUptodate(page))
 			goto success;
 	}
 
@@ -1635,20 +1598,20 @@
 
 	/* Somebody truncated the page on us? */
 	if (!page->mapping) {
-		UnlockPage(page);
+		unlock_page(page);
 		page_cache_release(page);
 		goto retry_all;
 	}
 
 	/* Somebody else successfully read it in? */
-	if (Page_Uptodate(page)) {
-		UnlockPage(page);
+	if (PageUptodate(page)) {
+		unlock_page(page);
 		goto success;
 	}
 	ClearPageError(page);
 	if (!mapping->a_ops->readpage(file, page)) {
-		wait_on_page(page);
-		if (Page_Uptodate(page))
+		wait_on_page_locked(page);
+		if (PageUptodate(page))
 			goto success;
 	}
 
@@ -2050,7 +2013,7 @@
 
 /*
  * Read into the page cache. If a page already exists,
- * and Page_Uptodate() is not set, try to fill the page.
+ * and PageUptodate() is not set, try to fill the page.
  */
 struct page *read_cache_page(struct address_space *mapping,
 				unsigned long index,
@@ -2065,17 +2028,17 @@
 	if (IS_ERR(page))
 		goto out;
 	mark_page_accessed(page);
-	if (Page_Uptodate(page))
+	if (PageUptodate(page))
 		goto out;
 
 	lock_page(page);
 	if (!page->mapping) {
-		UnlockPage(page);
+		unlock_page(page);
 		page_cache_release(page);
 		goto retry;
 	}
-	if (Page_Uptodate(page)) {
-		UnlockPage(page);
+	if (PageUptodate(page)) {
+		unlock_page(page);
 		goto out;
 	}
 	err = filler(data, page);
@@ -2320,11 +2283,12 @@
 		kunmap(page);
 		/* Mark it unlocked again and drop the page.. */
 		SetPageReferenced(page);
-		UnlockPage(page);
+		unlock_page(page);
 		page_cache_release(page);
 
 		if (status < 0)
 			break;
+		balance_dirty_pages_ratelimited(mapping);
 	} while (count);
 done:
 	*ppos = pos;
@@ -2355,7 +2319,7 @@
 	 * few blocks outside i_size.  Trim these off again.
 	 */
 	kunmap(page);
-	UnlockPage(page);
+	unlock_page(page);
 	page_cache_release(page);
 	if (pos + bytes > inode->i_size)
 		vmtruncate(inode, inode->i_size);
diff -Nru a/mm/memory.c b/mm/memory.c
--- a/mm/memory.c	Tue Apr 30 17:10:25 2002
+++ b/mm/memory.c	Tue Apr 30 17:10:25 2002
@@ -653,7 +653,7 @@
 		map = iobuf->maplist[i];
 		if (map) {
 			if (iobuf->locked)
-				UnlockPage(map);
+				unlock_page(map);
 			/* FIXME: cache flush missing for rw==READ
 			 * FIXME: call the correct reference counting function
 			 */
@@ -698,11 +698,11 @@
 			if (!page)
 				continue;
 			
-			if (TryLockPage(page)) {
+			if (TestSetPageLocked(page)) {
 				while (j--) {
 					struct page *tmp = *--ppage;
 					if (tmp)
-						UnlockPage(tmp);
+						unlock_page(tmp);
 				}
 				goto retry;
 			}
@@ -738,7 +738,7 @@
 			return -EINVAL;
 		
 		/* Try again...  */
-		wait_on_page(page);
+		wait_on_page_locked(page);
 	}
 	
 	if (++repeat < 16)
@@ -768,7 +768,7 @@
 			page = *ppage;
 			if (!page)
 				continue;
-			UnlockPage(page);
+			unlock_page(page);
 		}
 	}
 	return 0;
@@ -982,7 +982,7 @@
 	if (!VALID_PAGE(old_page))
 		goto bad_wp_page;
 
-	if (!TryLockPage(old_page)) {
+	if (!TestSetPageLocked(old_page)) {
 		int reuse = can_share_swap_page(old_page);
 		unlock_page(old_page);
 		if (reuse) {
diff -Nru a/mm/mincore.c b/mm/mincore.c
--- a/mm/mincore.c	Tue Apr 30 17:10:25 2002
+++ b/mm/mincore.c	Tue Apr 30 17:10:25 2002
@@ -31,7 +31,7 @@
 
 	page = find_get_page(as, pgoff);
 	if (page) {
-		present = Page_Uptodate(page);
+		present = PageUptodate(page);
 		page_cache_release(page);
 	}
 
diff -Nru a/mm/mmap.c b/mm/mmap.c
--- a/mm/mmap.c	Tue Apr 30 17:10:23 2002
+++ b/mm/mmap.c	Tue Apr 30 17:10:23 2002
@@ -69,7 +69,7 @@
 	    return 1;
 
 	/* The page cache contains buffer pages these days.. */
-	free = atomic_read(&page_cache_size);
+	free = get_page_cache_size();
 	free += nr_free_pages();
 	free += nr_swap_pages;
 
diff -Nru a/mm/msync.c b/mm/msync.c
--- a/mm/msync.c	Tue Apr 30 17:10:25 2002
+++ b/mm/msync.c	Tue Apr 30 17:10:25 2002
@@ -138,19 +138,21 @@
 
 		if (!ret && (flags & (MS_SYNC|MS_ASYNC))) {
 			struct inode * inode = file->f_dentry->d_inode;
+			int err;
 
 			down(&inode->i_sem);
-			ret = filemap_fdatasync(inode->i_mapping);
+			ret = filemap_fdatawait(inode->i_mapping);
+			err = filemap_fdatawrite(inode->i_mapping);
+			if (!ret)
+				ret = err;
 			if (flags & MS_SYNC) {
-				int err;
-
 				if (file->f_op && file->f_op->fsync) {
 					err = file->f_op->fsync(file, file->f_dentry, 1);
 					if (err && !ret)
 						ret = err;
 				}
 				err = filemap_fdatawait(inode->i_mapping);
-				if (err && !ret)
+				if (!ret)
 					ret = err;
 			}
 			up(&inode->i_sem);
diff -Nru a/mm/page-writeback.c b/mm/page-writeback.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/mm/page-writeback.c	Tue Apr 30 17:10:25 2002
@@ -0,0 +1,527 @@
+/*
+ * mm/page-writeback.c.
+ *
+ * Copyright (C) 2002, Linus Torvalds.
+ *
+ * Contains functions related to writing back dirty pages at the
+ * address_space level.
+ *
+ * 10Apr2002	akpm@zip.com.au
+ *		Initial version
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+#include <linux/writeback.h>
+#include <linux/init.h>
+#include <linux/sysrq.h>
+
+/*
+ * Memory thresholds, in percentages
+ * FIXME: expose these via /proc or whatever.
+ */
+
+/*
+ * Start background writeback (via pdflush) at this level
+ */
+static int dirty_background_ratio = 30;
+
+/*
+ * The generator of dirty data starts async writeback at this level
+ */
+static int dirty_async_ratio = 45;
+
+/*
+ * The generator of dirty data performs sync writeout at this level
+ */
+static int dirty_sync_ratio = 60;
+
+/*
+ * balance_dirty_pages() must be called by processes which are
+ * generating dirty data.  It looks at the number of dirty pages
+ * in the machine and either:
+ *
+ * - Starts background writeback or
+ * - Causes the caller to perform async writeback or
+ * - Causes the caller to perform synchronous writeback, then
+ *   tells a pdflush thread to perform more writeback or
+ * - Does nothing at all.
+ *
+ * balance_dirty_pages() can sleep.
+ */
+void balance_dirty_pages(struct address_space *mapping)
+{
+	const int tot = nr_free_pagecache_pages();
+	struct page_state ps;
+	int background_thresh;
+	int async_thresh;
+	int sync_thresh;
+	int wake_pdflush = 0;
+	unsigned long dirty_and_locked;
+
+	get_page_state(&ps);
+	dirty_and_locked = ps.nr_dirty + ps.nr_locked;
+
+	background_thresh = (dirty_background_ratio * tot) / 100;
+	async_thresh = (dirty_async_ratio * tot) / 100;
+	sync_thresh = (dirty_sync_ratio * tot) / 100;
+
+	if (dirty_and_locked > sync_thresh) {
+		int nr_to_write = dirty_and_locked - async_thresh;
+
+		writeback_unlocked_inodes(&nr_to_write, WB_SYNC_LAST, NULL);
+		wake_pdflush = 1;
+	} else if (dirty_and_locked > async_thresh) {
+		int nr_to_write = dirty_and_locked - async_thresh;
+
+		writeback_unlocked_inodes(&nr_to_write, WB_SYNC_NONE, NULL);
+	} else if (dirty_and_locked > background_thresh) {
+		wake_pdflush = 1;
+	}
+
+	if (wake_pdflush && !IS_FLUSHING(mapping->host)) {
+		/*
+		 * There is no flush thread against this device. Start one now.
+		 */
+		get_page_state(&ps);
+		if (ps.nr_dirty > 0) {
+			pdflush_flush(ps.nr_dirty);
+			yield();
+		}
+	}
+}
+
+/*
+ * Front-end to balance_dirty_pages - just to make sure it's not called
+ * too often.
+ */
+void balance_dirty_pages_ratelimited(struct address_space *mapping)
+{
+	static struct rate_limit_struct {
+		int count;
+	} ____cacheline_aligned ratelimits[NR_CPUS];
+	int cpu;
+
+	preempt_disable();
+	cpu = smp_processor_id();
+	if (ratelimits[cpu].count++ >= 32) {
+		ratelimits[cpu].count = 0;
+		preempt_enable();
+		balance_dirty_pages(mapping);
+		return;
+	}
+	preempt_enable();
+}
+
+/*
+ * Here are some applications of the pdflush thread pool
+ */
+
+/*
+ * Start heavy writeback of everything.  This is the analogue of the old
+ * wakeup_bdflush().  Returns zero if a thread was successfully launched.
+ *
+ * Is passed in the number of pages to write.
+ *
+ * We yield, to allow page allocators to perform their I/O against large files.
+ */
+
+static void pdflush_bdflush(unsigned long arg)
+{
+	int nr_pages = arg;
+
+	CHECK_EMERGENCY_SYNC
+
+	while (nr_pages) {
+		int nr_to_write = WRITEOUT_PAGES;
+
+		if (nr_to_write > nr_pages)
+			nr_to_write = nr_pages;
+		nr_pages -= nr_to_write;
+		writeback_unlocked_inodes(&nr_to_write, WB_SYNC_NONE, NULL);
+		yield();
+	}
+	run_task_queue(&tq_disk);
+}
+
+int pdflush_flush(unsigned long nr_pages)
+{
+	return pdflush_operation(pdflush_bdflush, nr_pages);
+}
+
+/*
+ * The interval between `kupdate'-style writebacks.
+ *
+ * Traditional kupdate writes back data which is 30-35 seconds old.
+ * This one does that, but it also writes back just 1/6th of the dirty
+ * data.  This is to avoid great I/O storms.
+ *
+ * We chunk the writes up and yield, to permit any throttled page-allocators
+ * to perform their I/O against a large file.
+ */
+static int wb_writeback_jifs = 5 * HZ;
+
+/*
+ * Periodic writeback of "old" data.
+ *
+ * Define "old": the first time one of an inode's pages is dirtied, we mark the
+ * dirtying-time in the inode's address_space.  So this periodic writeback code
+ * just walks the superblock inode list, writing back any inodes which are
+ * older than a specific point in time.
+ *
+ * Spot the bug: at jiffies wraparound, the attempt to set the inode's dirtying
+ * time won't work, because zero means not-dirty.  That's OK. The data will get
+ * written out later by the VM (at least).
+ *
+ * We also limit the number of pages which are written out, to avoid writing
+ * huge amounts of data against a single file, which would cause memory
+ * allocators to block for too long.
+ */
+static void wb_kupdate(unsigned long arg)
+{
+	unsigned long oldest_jif = jiffies - 30*HZ;
+	struct page_state ps;
+	int total_to_write;
+	int nr_to_write;
+
+	sync_supers();
+
+	get_page_state(&ps);
+
+	total_to_write = ps.nr_dirty / 6;
+	if (total_to_write < 16384) {
+		total_to_write = 16384;
+		if (total_to_write > ps.nr_dirty)
+			total_to_write = ps.nr_dirty;
+	}
+	while (total_to_write > 0) {
+		nr_to_write = total_to_write;
+		if (nr_to_write > WRITEOUT_PAGES)
+			nr_to_write = WRITEOUT_PAGES;
+		total_to_write -= nr_to_write;
+		writeback_unlocked_inodes(&nr_to_write,
+				WB_SYNC_NONE, &oldest_jif);
+		yield();
+	}
+	run_task_queue(&tq_disk);
+}
+
+/*
+ * The writeback timer, for kupdate-style functionality
+ */
+static struct timer_list wb_timer;
+
+static void wb_timer_fn(unsigned long unused)
+{
+	mod_timer(&wb_timer, jiffies + wb_writeback_jifs);
+	pdflush_operation(wb_kupdate, 0);
+}
+
+static int __init wb_timer_init(void)
+{
+	init_timer(&wb_timer);
+	wb_timer.expires = jiffies + wb_writeback_jifs;
+	wb_timer.data = 0;
+	wb_timer.function = wb_timer_fn;
+	add_timer(&wb_timer);
+	return 0;
+}
+module_init(wb_timer_init);
+
+/*
+ * FIXME: PG_launder gets cleared by accident.
+ */
+static int writeback_mapping(struct page *page, int *nr_to_write)
+{
+	struct inode *inode = page->mapping->host;
+
+	SetPageDirty(page);
+
+	/*
+	 * We don't own this inode, so we don't want the address_space
+	 * vanishing while writeback is walking the list
+	 */
+	inode = igrab(inode);
+	unlock_page(page);
+
+	if (inode) {
+		writeback_single_inode(inode, 0, nr_to_write);
+
+		/*
+		 * This iput() will internally call ext2_discard_prealloc(),
+		 * which is rather bogus.  But there is no other way of
+		 * dropping our ref to the inode.  However, there's no harm
+		 * in dropping the prealloc, because there probably isn't any.
+		 * Just a waste of cycles.
+		 */
+		iput(inode);
+	}
+	return 0;
+}
+
+/*
+ * A library function, which implements the vm_writeback a_op.  It's fairly
+ * lame at this time.  The idea is: the VM wants to liberate this page,
+ * so we pass the page to the address_space and give the fs the opportunity
+ * to write out lots of pages around this one.  It allows extent-based
+ * filesytems to do intelligent things.  It lets delayed-allocate filesystems
+ * perform better file layout.  It lets the address_space opportunistically
+ * write back disk-contiguous pages which are in other zones.
+ */
+int generic_vm_writeback(struct page *page, int *nr_to_write)
+{
+	return writeback_mapping(page, nr_to_write);
+}
+EXPORT_SYMBOL(generic_vm_writeback);
+
+/**
+ * generic_writeback_mapping - walk the list of dirty pages of the given
+ * address space and writepage() all of them.
+ * 
+ * @mapping: address space structure to write
+ * @nr_to_write: subtract the number of written pages from *@nr_to_write
+ *
+ * This is a library function, which implements the writeback_mapping()
+ * address_space_operation for filesystems which are using multipage BIO
+ * writeback.
+ *
+ * (The next two paragraphs refer to code which isn't here yet, but they
+ *  explain the presence of address_space.io_pages)
+ *
+ * Pages can be moved from clean_pages or locked_pages onto dirty_pages
+ * at any time - it's not possible to lock against that.  So pages which
+ * have already been added to a BIO may magically reappear on the dirty_pages
+ * list.  And generic_writeback_mapping() will again try to lock those pages.
+ * But I/O has not yet been started against the page.  Thus deadlock.
+ *
+ * To avoid this, the entire contents of the dirty_pages list are moved
+ * onto io_pages up-front.  We then walk io_pages, locking the
+ * pages and submitting them for I/O, moving them to locked_pages.
+ *
+ * This has the added benefit of preventing a livelock which would otherwise
+ * occur if pages are being dirtied faster than we can write them out.
+ *
+ * If a page is already under I/O, generic_writeback_mapping() skips it, even
+ * if it's dirty.  This is desirable behaviour for memory-cleaning writeback,
+ * but it is INCORRECT for data-integrity system calls such as fsync().  fsync()
+ * and msync() need to guarentee that all the data which was dirty at the time
+ * the call was made get new I/O started against them.  The way to do this is
+ * to run filemap_fdatawait() before calling filemap_fdatawrite().
+ *
+ * It's fairly rare for PageWriteback pages to be on ->dirty_pages.  It
+ * means that someone redirtied the page while it was under I/O.
+ */
+int generic_writeback_mapping(struct address_space *mapping, int *nr_to_write)
+{
+	int ret = 0;
+	int done = 0;
+	int err;
+	int (*writepage)(struct page *) = mapping->a_ops->writepage;
+
+	write_lock(&mapping->page_lock);
+
+	list_splice(&mapping->dirty_pages, &mapping->io_pages);
+	INIT_LIST_HEAD(&mapping->dirty_pages);
+	mapping->dirtied_when = 0;
+
+        while (!list_empty(&mapping->io_pages) && !done) {
+		struct page *page = list_entry(mapping->io_pages.prev,
+					struct page, list);
+		list_del(&page->list);
+		if (PageWriteback(page)) {
+			if (PageDirty(page)) {
+				list_add(&page->list, &mapping->dirty_pages);
+				continue;
+			}
+			list_add(&page->list, &mapping->locked_pages);
+			continue;
+		}
+		if (!PageDirty(page)) {
+			list_add(&page->list, &mapping->clean_pages);
+			continue;
+		}
+		list_add(&page->list, &mapping->locked_pages);
+
+		page_cache_get(page);
+		write_unlock(&mapping->page_lock);
+
+		lock_page(page);
+
+		if (TestClearPageDirty(page)) {
+			err = writepage(page);
+			if (!ret)
+				ret = err;
+			if (nr_to_write) {
+				--(*nr_to_write);
+				if (*nr_to_write <= 0)
+					done = 1;
+			}
+		} else {
+			unlock_page(page);
+		}
+
+		page_cache_release(page);
+		write_lock(&mapping->page_lock);
+	}
+	if (!list_empty(&mapping->io_pages)) {
+		/*
+		 * Put the rest back, in the correct order.
+		 */
+		list_splice(&mapping->io_pages, mapping->dirty_pages.prev);
+		INIT_LIST_HEAD(&mapping->io_pages);
+	}
+	write_unlock(&mapping->page_lock);
+	return ret;
+}
+EXPORT_SYMBOL(generic_writeback_mapping);
+
+/**
+ * write_one_page - write out a single page and optionally wait on I/O
+ *
+ * @page - the page to write
+ * @wait - if true, wait on writeout
+ *
+ * The page must be locked by the caller and will come unlocked when I/O
+ * completes.
+ *
+ * write_one_page() returns a negative error code if I/O failed.
+ */
+int write_one_page(struct page *page, int wait)
+{
+	struct address_space *mapping = page->mapping;
+	int ret = 0;
+
+	BUG_ON(!PageLocked(page));
+
+	if (wait && PageWriteback(page))
+		wait_on_page_writeback(page);
+
+	write_lock(&mapping->page_lock);
+	list_del(&page->list);
+	if (TestClearPageDirty(page)) {
+		list_add(&page->list, &mapping->locked_pages);
+		page_cache_get(page);
+		write_unlock(&mapping->page_lock);
+		ret = mapping->a_ops->writepage(page);
+		if (ret == 0 && wait) {
+			wait_on_page_writeback(page);
+			if (PageError(page))
+				ret = -EIO;
+		}
+		page_cache_release(page);
+	} else {
+		list_add(&page->list, &mapping->clean_pages);
+		write_unlock(&mapping->page_lock);
+		unlock_page(page);
+	}
+	return ret;
+}
+EXPORT_SYMBOL(write_one_page);
+
+/*
+ * Add a page to the dirty page list.
+ *
+ * It is a sad fact of life that this function is called from several places
+ * deeply under spinlocking.  It may not sleep.
+ *
+ * If the page has buffers, the uptodate buffers are set dirty, to preserve
+ * dirty-state coherency between the page and the buffers.  It the page does
+ * not have buffers then when they are later attached they will all be set
+ * dirty.
+ *
+ * The buffers are dirtied before the page is dirtied.  There's a small race
+ * window in which a writepage caller may see the page cleanness but not the
+ * buffer dirtiness.  That's fine.  If this code were to set the page dirty
+ * before the buffers, a concurrent writepage caller could clear the page dirty
+ * bit, see a bunch of clean buffers and we'd end up with dirty buffers/clean
+ * page on the dirty page list.
+ *
+ * There is also a small window where the page is dirty, and not on dirty_pages.
+ * Also a possibility that by the time the page is added to dirty_pages, it has
+ * been set clean.  The page lists are somewhat approximate in this regard.
+ * It's better to have clean pages accidentally attached to dirty_pages than to
+ * leave dirty pages attached to clean_pages.
+ *
+ * We use i_bufferlist_lock to lock against try_to_free_buffers while using the
+ * page's buffer list.  Also use this to protect against clean buffers being
+ * added to the page after it was set dirty.
+ *
+ * FIXME: may need to call ->reservepage here as well.  That's rather up to the
+ * address_space though.
+ */
+int __set_page_dirty_buffers(struct page *page)
+{
+	int ret = 0;
+	struct address_space *mapping = page->mapping;
+	struct inode *inode;
+
+	if (mapping == NULL) {
+		SetPageDirty(page);
+		goto out;
+	}
+
+	inode = mapping->host;
+
+	spin_lock(&inode->i_bufferlist_lock);
+
+	if (page_has_buffers(page)) {
+		struct buffer_head *head = page_buffers(page);
+		struct buffer_head *bh = head;
+
+		do {
+			if (buffer_uptodate(bh))
+				set_buffer_dirty(bh);
+			bh = bh->b_this_page;
+		} while (bh != head);
+	}
+
+	if (!TestSetPageDirty(page)) {
+		write_lock(&mapping->page_lock);
+		list_del(&page->list);
+		list_add(&page->list, &mapping->dirty_pages);
+		write_unlock(&mapping->page_lock);
+		__mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
+	}
+	
+	spin_unlock(&inode->i_bufferlist_lock);
+out:
+	return ret;
+}
+EXPORT_SYMBOL(__set_page_dirty_buffers);
+
+/*
+ * For address_spaces which do not use buffers.  Just set the page's dirty bit
+ * and move it to the dirty_pages list.  Also perform space reservation if
+ * required.
+ *
+ * __set_page_dirty_nobuffers() may return -ENOSPC.  But if it does, the page
+ * is still safe, as long as it actually manages to find some blocks at
+ * writeback time.
+ *
+ * This is also used when a single buffer is being dirtied: we want to set the
+ * page dirty in that case, but not all the buffers.  This is a "bottom-up"
+ * dirtying, whereas __set_page_dirty_buffers() is a "top-down" dirtying.
+ */
+int __set_page_dirty_nobuffers(struct page *page)
+{
+	int ret = 0;
+
+	if (!TestSetPageDirty(page)) {
+		struct address_space *mapping = page->mapping;
+
+		if (mapping) {
+			write_lock(&mapping->page_lock);
+			list_del(&page->list);
+			list_add(&page->list, &mapping->dirty_pages);
+			write_unlock(&mapping->page_lock);
+			__mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
+		}
+	}
+	return ret;
+}
+EXPORT_SYMBOL(__set_page_dirty_nobuffers);
diff -Nru a/mm/page_alloc.c b/mm/page_alloc.c
--- a/mm/page_alloc.c	Tue Apr 30 17:10:23 2002
+++ b/mm/page_alloc.c	Tue Apr 30 17:10:23 2002
@@ -103,15 +103,16 @@
 		BUG();
 	if (!VALID_PAGE(page))
 		BUG();
-	if (PageSwapCache(page))
-		BUG();
 	if (PageLocked(page))
 		BUG();
 	if (PageLRU(page))
 		BUG();
 	if (PageActive(page))
 		BUG();
-	page->flags &= ~((1<<PG_referenced) | (1<<PG_dirty));
+	if (PageWriteback(page))
+		BUG();
+	ClearPageDirty(page);
+	page->flags &= ~(1<<PG_referenced);
 
 	if (current->flags & PF_FREE_PAGES)
 		goto local_freelist;
@@ -296,8 +297,6 @@
 						BUG();
 					if (!VALID_PAGE(page))
 						BUG();
-					if (PageSwapCache(page))
-						BUG();
 					if (PageLocked(page))
 						BUG();
 					if (PageLRU(page))
@@ -306,6 +305,8 @@
 						BUG();
 					if (PageDirty(page))
 						BUG();
+					if (PageWriteback(page))
+						BUG();
 
 					break;
 				}
@@ -394,12 +395,15 @@
 			if (page)
 				return page;
 		}
+nopage:
+		printk("%s: page allocation failure. order:%d, mode:0x%x\n",
+			current->comm, order, gfp_mask);
 		return NULL;
 	}
 
 	/* Atomic allocations - we can't balance anything */
 	if (!(gfp_mask & __GFP_WAIT))
-		return NULL;
+		goto nopage;
 
 	page = balance_classzone(classzone, gfp_mask, order, &freed);
 	if (page)
@@ -422,7 +426,7 @@
 
 	/* Don't let big-order allocations loop */
 	if (order > 3)
-		return NULL;
+		goto nopage;
 
 	/* Yield for kswapd, and try again */
 	__set_current_state(TASK_RUNNING);
@@ -521,6 +525,33 @@
 	return sum;
 }
 
+/*
+ * Amount of free RAM allocatable as pagecache memory:
+ */
+unsigned int nr_free_pagecache_pages(void)
+{
+	pg_data_t *pgdat = pgdat_list;
+	unsigned int sum = 0;
+
+	do {
+		zonelist_t *zonelist = pgdat->node_zonelists +
+				(GFP_HIGHUSER & GFP_ZONEMASK);
+		zone_t **zonep = zonelist->zones;
+		zone_t *zone;
+
+		for (zone = *zonep++; zone; zone = *zonep++) {
+			unsigned long size = zone->size;
+			unsigned long high = zone->pages_high;
+			if (size > high)
+				sum += size - high;
+		}
+
+		pgdat = pgdat->node_next;
+	} while (pgdat);
+
+	return sum;
+}
+
 #if CONFIG_HIGHMEM
 unsigned int nr_free_highpages (void)
 {
@@ -535,6 +566,45 @@
 }
 #endif
 
+unsigned long nr_buffermem_pages(void)
+{
+	return atomic_read(&buffermem_pages);
+}
+
+/*
+ * Accumulate the page_state information across all CPUs.
+ * The result is unavoidably approximate - it can change
+ * during and after execution of this function.
+ */
+struct page_state page_states[NR_CPUS] __cacheline_aligned;
+EXPORT_SYMBOL(page_states);
+
+void get_page_state(struct page_state *ret)
+{
+	int pcpu;
+
+	ret->nr_dirty = 0;
+	ret->nr_locked = 0;
+	ret->nr_pagecache = 0;
+
+	for (pcpu = 0; pcpu < smp_num_cpus; pcpu++) {
+		struct page_state *ps;
+
+		ps = &page_states[cpu_logical_map(pcpu)];
+		ret->nr_dirty += ps->nr_dirty;
+		ret->nr_locked += ps->nr_locked;
+		ret->nr_pagecache += ps->nr_pagecache;
+	}
+}
+
+unsigned long get_page_cache_size(void)
+{
+	struct page_state ps;
+
+	get_page_state(&ps);
+	return ps.nr_pagecache;
+}
+
 #define K(x) ((x) << (PAGE_SHIFT-10))
 
 /*
@@ -814,7 +884,7 @@
 			struct page *page = mem_map + offset + i;
 			set_page_zone(page, nid * MAX_NR_ZONES + j);
 			set_page_count(page, 0);
-			__SetPageReserved(page);
+			SetPageReserved(page);
 			memlist_init(&page->list);
 			if (j != ZONE_HIGHMEM)
 				set_page_address(page, __va(zone_start_paddr));
diff -Nru a/mm/page_io.c b/mm/page_io.c
--- a/mm/page_io.c	Tue Apr 30 17:10:23 2002
+++ b/mm/page_io.c	Tue Apr 30 17:10:23 2002
@@ -96,10 +96,8 @@
 		PAGE_BUG(page);
 	if (!PageSwapCache(page))
 		PAGE_BUG(page);
-	if (page->mapping != &swapper_space)
-		PAGE_BUG(page);
 	if (!rw_swap_page_base(rw, entry, page))
-		UnlockPage(page);
+		unlock_page(page);
 }
 
 /*
@@ -113,14 +111,15 @@
 	
 	if (!PageLocked(page))
 		PAGE_BUG(page);
-	if (PageSwapCache(page))
-		PAGE_BUG(page);
 	if (page->mapping)
 		PAGE_BUG(page);
 	/* needs sync_page to wait I/O completation */
 	page->mapping = &swapper_space;
 	if (!rw_swap_page_base(rw, entry, page))
-		UnlockPage(page);
-	wait_on_page(page);
+		unlock_page(page);
+	if (rw == WRITE)
+		wait_on_page_writeback(page);
+	else
+		wait_on_page_locked(page);
 	page->mapping = NULL;
 }
diff -Nru a/mm/pdflush.c b/mm/pdflush.c
--- a/mm/pdflush.c	Tue Apr 30 17:10:25 2002
+++ b/mm/pdflush.c	Tue Apr 30 17:10:25 2002
@@ -56,7 +56,7 @@
  *
  * Thread pool management algorithm:
  * 
- * - The minumum and maximum number of pdflush instances are bound
+ * - The minimum and maximum number of pdflush instances are bound
  *   by MIN_PDFLUSH_THREADS and MAX_PDFLUSH_THREADS.
  * 
  * - If there have been no idle pdflush instances for 1 second, create
@@ -155,8 +155,8 @@
 /*
  * Of course, my_work wants to be just a local in __pdflush().  It is
  * separated out in this manner to hopefully prevent the compiler from
- * performing unfortunate optimisations agains the auto variables.  Because
- * there are visible to other tasks and CPUs.  (No problem has actually
+ * performing unfortunate optimisations against the auto variables.  Because
+ * these are visible to other tasks and CPUs.  (No problem has actually
  * been observed.  This is just paranoia).
  */
 static int pdflush(void *dummy)
diff -Nru a/mm/readahead.c b/mm/readahead.c
--- a/mm/readahead.c	Tue Apr 30 17:10:23 2002
+++ b/mm/readahead.c	Tue Apr 30 17:10:23 2002
@@ -12,39 +12,19 @@
 #include <linux/mm.h>
 #include <linux/blkdev.h>
 
-/*
- * The readahead logic manages two readahead windows.  The "current"
- * and the "ahead" windows.
- *
- * VM_MAX_READAHEAD specifies, in kilobytes, the maximum size of
- * each of the two windows.  So the amount of readahead which is
- * in front of the file pointer varies between VM_MAX_READAHEAD and
- * VM_MAX_READAHEAD * 2.
- *
- * VM_MAX_READAHEAD only applies if the underlying request queue
- * has a zero value of ra_sectors.
- */
+unsigned long default_ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
 
 /*
  * Return max readahead size for this inode in number-of-pages.
  */
-static int get_max_readahead(struct inode *inode)
+static inline unsigned long get_max_readahead(struct file *file)
 {
-	unsigned blk_ra_kbytes = 0;
-
-	if (inode->i_sb->s_bdev) {
-		blk_ra_kbytes = blk_get_readahead(inode->i_sb->s_bdev) / 2;
-	}
-	return blk_ra_kbytes >> (PAGE_CACHE_SHIFT - 10);
+	return file->f_ra.ra_pages;
 }
 
-static int get_min_readahead(struct inode *inode)
+static inline unsigned long get_min_readahead(struct file *file)
 {
-	int ret = VM_MIN_READAHEAD / PAGE_CACHE_SIZE;
-
-	if (ret < 2)
-		ret = 2;
-	return ret;
+	return (VM_MIN_READAHEAD * 1024) / PAGE_CACHE_SIZE;
 }
 
 /*
@@ -173,7 +153,7 @@
 	}
 
 	/*
-	 * Do this now, rather than at the next wait_on_page().
+	 * Do this now, rather than at the next wait_on_page_locked().
 	 */
 	run_task_queue(&tq_disk);
 
@@ -189,7 +169,6 @@
  */
 void page_cache_readahead(struct file *file, unsigned long offset)
 {
-	struct inode *inode = file->f_dentry->d_inode->i_mapping->host;
 	struct file_ra_state *ra = &file->f_ra;
 	unsigned long max;
 	unsigned long min;
@@ -206,10 +185,10 @@
 			goto out;
 	}
 
-	max = get_max_readahead(inode);
+	max = get_max_readahead(file);
 	if (max == 0)
 		goto out;	/* No readahead */
-	min = get_min_readahead(inode);
+	min = get_min_readahead(file);
 
 	if (ra->next_size == 0 && offset == 0) {
 		/*
@@ -309,9 +288,9 @@
  */
 void page_cache_readaround(struct file *file, unsigned long offset)
 {
+	const unsigned long min = get_min_readahead(file) * 2;
 	unsigned long target;
 	unsigned long backward;
-	const int min = get_min_readahead(file->f_dentry->d_inode->i_mapping->host) * 2;
 
 	if (file->f_ra.next_size < min)
 		file->f_ra.next_size = min;
@@ -338,8 +317,7 @@
  */
 void handle_ra_thrashing(struct file *file)
 {
-	struct address_space * mapping = file->f_dentry->d_inode->i_mapping;
-	const unsigned long min = get_min_readahead(mapping->host);
+	const unsigned long min = get_min_readahead(file);
 
 	file->f_ra.next_size -= 3;
 	if (file->f_ra.next_size < min)
diff -Nru a/mm/shmem.c b/mm/shmem.c
--- a/mm/shmem.c	Tue Apr 30 17:10:25 2002
+++ b/mm/shmem.c	Tue Apr 30 17:10:25 2002
@@ -466,7 +466,7 @@
 		spin_unlock(&info->lock);
 		SetPageUptodate(page);
 		set_page_dirty(page);
-		UnlockPage(page);
+		unlock_page(page);
 		return 0;
 	}
 
@@ -512,7 +512,7 @@
 
 	page = find_get_page(mapping, idx);
 	if (page) {
-		if (TryLockPage(page))
+		if (TestSetPageLocked(page))
 			goto wait_retry;
 		spin_unlock (&info->lock);
 		return page;
@@ -532,8 +532,8 @@
 					goto repeat;
 				return ERR_PTR(-ENOMEM);
 			}
-			wait_on_page(page);
-			if (!Page_Uptodate(page) && entry->val == swap.val) {
+			wait_on_page_locked(page);
+			if (!PageUptodate(page) && entry->val == swap.val) {
 				page_cache_release(page);
 				return ERR_PTR(-EIO);
 			}
@@ -545,12 +545,12 @@
 		}
 
 		/* We have to do this with page locked to prevent races */
-		if (TryLockPage(page)) 
+		if (TestSetPageLocked(page)) 
 			goto wait_retry;
 
 		error = move_from_swap_cache(page, idx, mapping);
 		if (error < 0) {
-			UnlockPage(page);
+			unlock_page(page);
 			return ERR_PTR(error);
 		}
 
@@ -595,7 +595,7 @@
 
 wait_retry:
 	spin_unlock (&info->lock);
-	wait_on_page(page);
+	wait_on_page_locked(page);
 	page_cache_release(page);
 	goto repeat;
 }
@@ -614,7 +614,7 @@
 	if (IS_ERR (*ptr))
 		goto failed;
 
-	UnlockPage(*ptr);
+	unlock_page(*ptr);
 	up (&info->sem);
 	return 0;
 failed:
@@ -864,7 +864,7 @@
 		}
 unlock:
 		/* Mark it unlocked again and drop the page.. */
-		UnlockPage(page);
+		unlock_page(page);
 		page_cache_release(page);
 
 		if (status < 0)
@@ -1140,7 +1140,7 @@
 		memcpy(kaddr, symname, len);
 		kunmap(page);
 		SetPageDirty(page);
-		UnlockPage(page);
+		unlock_page(page);
 		page_cache_release(page);
 		up(&info->sem);
 		inode->i_op = &shmem_symlink_inode_operations;
diff -Nru a/mm/slab.c b/mm/slab.c
--- a/mm/slab.c	Tue Apr 30 17:10:25 2002
+++ b/mm/slab.c	Tue Apr 30 17:10:25 2002
@@ -544,7 +544,7 @@
 	 * vm_scan(). Shouldn't be a worry.
 	 */
 	while (i--) {
-		PageClearSlab(page);
+		ClearPageSlab(page);
 		page++;
 	}
 	free_pages((unsigned long)addr, cachep->gfporder);
@@ -1198,7 +1198,7 @@
 	do {
 		SET_PAGE_CACHE(page, cachep);
 		SET_PAGE_SLAB(page, slabp);
-		PageSetSlab(page);
+		SetPageSlab(page);
 		page++;
 	} while (--i);
 
diff -Nru a/mm/swap_state.c b/mm/swap_state.c
--- a/mm/swap_state.c	Tue Apr 30 17:10:25 2002
+++ b/mm/swap_state.c	Tue Apr 30 17:10:25 2002
@@ -24,7 +24,7 @@
 static int swap_writepage(struct page *page)
 {
 	if (remove_exclusive_swap_page(page)) {
-		UnlockPage(page);
+		unlock_page(page);
 		return 0;
 	}
 	rw_swap_page(WRITE, page);
@@ -36,12 +36,23 @@
 	sync_page: block_sync_page,
 };
 
+/*
+ * swapper_inode is needed only for for i_bufferlist_lock. This
+ * avoid special-casing in other parts of the kernel.
+ */
+static struct inode swapper_inode = {
+	i_bufferlist_lock:	SPIN_LOCK_UNLOCKED,
+	i_mapping:		&swapper_space,
+};
+
 struct address_space swapper_space = {
 	page_tree:	RADIX_TREE_INIT(GFP_ATOMIC),
 	page_lock:	RW_LOCK_UNLOCKED,
 	clean_pages:	LIST_HEAD_INIT(swapper_space.clean_pages),
 	dirty_pages:	LIST_HEAD_INIT(swapper_space.dirty_pages),
+	io_pages:	LIST_HEAD_INIT(swapper_space.io_pages),
 	locked_pages:	LIST_HEAD_INIT(swapper_space.locked_pages),
+	host:		&swapper_inode,
 	a_ops:		&swap_aops,
 	i_shared_lock:	SPIN_LOCK_UNLOCKED,
 };
@@ -159,10 +170,11 @@
 
 		/* Add it to the swap cache */
 		*pslot = page;
-		page->flags = ((page->flags & ~(1 << PG_uptodate | 1 << PG_error
-						| 1 << PG_dirty  | 1 << PG_referenced
-						| 1 << PG_arch_1 | 1 << PG_checked))
-			       | (1 << PG_locked));
+		page->flags &= ~(1 << PG_uptodate | 1 << PG_error
+				| 1 << PG_referenced | 1 << PG_arch_1
+				| 1 << PG_checked);
+		SetPageLocked(page);
+		ClearPageDirty(page);
 		___add_to_page_cache(page, &swapper_space, entry.val);
 	}
 
@@ -207,7 +219,7 @@
 		page->flags &= ~(1 << PG_uptodate | 1 << PG_error |
 				 1 << PG_referenced | 1 << PG_arch_1 |
 				 1 << PG_checked);
-		page->flags |= (1 << PG_dirty);
+		SetPageDirty(page);
 		___add_to_page_cache(page, mapping, index);
 	}
 
@@ -232,9 +244,9 @@
 	 * exclusive_swap_page() _with_ the lock. 
 	 * 					- Marcelo
 	 */
-	if (PageSwapCache(page) && !TryLockPage(page)) {
+	if (PageSwapCache(page) && !TestSetPageLocked(page)) {
 		remove_exclusive_swap_page(page);
-		UnlockPage(page);
+		unlock_page(page);
 	}
 	page_cache_release(page);
 }
diff -Nru a/mm/swapfile.c b/mm/swapfile.c
--- a/mm/swapfile.c	Tue Apr 30 17:10:25 2002
+++ b/mm/swapfile.c	Tue Apr 30 17:10:25 2002
@@ -348,7 +348,7 @@
 			delete_from_swap_cache(page);
 			SetPageDirty(page);
 		}
-		UnlockPage(page);
+		unlock_page(page);
 		page_cache_release(page);
 	}
 }
@@ -589,11 +589,12 @@
 		 * Wait for and lock page.  When do_swap_page races with
 		 * try_to_unuse, do_swap_page can handle the fault much
 		 * faster than try_to_unuse can locate the entry.  This
-		 * apparently redundant "wait_on_page" lets try_to_unuse
+		 * apparently redundant "wait_on_page_locked" lets try_to_unuse
 		 * defer to do_swap_page in such a case - in some tests,
 		 * do_swap_page and try_to_unuse repeatedly compete.
 		 */
-		wait_on_page(page);
+		wait_on_page_locked(page);
+		wait_on_page_writeback(page);
 		lock_page(page);
 
 		/*
@@ -689,7 +690,7 @@
 		 * mark page dirty so try_to_swap_out will preserve it.
 		 */
 		SetPageDirty(page);
-		UnlockPage(page);
+		unlock_page(page);
 		page_cache_release(page);
 
 		/*
diff -Nru a/mm/vmscan.c b/mm/vmscan.c
--- a/mm/vmscan.c	Tue Apr 30 17:10:23 2002
+++ b/mm/vmscan.c	Tue Apr 30 17:10:23 2002
@@ -21,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/highmem.h>
 #include <linux/file.h>
+#include <linux/writeback.h>
 #include <linux/compiler.h>
 
 #include <asm/pgalloc.h>
@@ -34,6 +35,11 @@
  */
 #define DEF_PRIORITY (6)
 
+static inline int is_page_cache_freeable(struct page * page)
+{
+	return page_count(page) - !!PagePrivate(page) == 1;
+}
+
 /*
  * On the swap_out path, the radix-tree node allocations are performing
  * GFP_ATOMIC allocations under PF_MEMALLOC.  They can completely
@@ -86,9 +92,12 @@
 	if (!memclass(page_zone(page), classzone))
 		return 0;
 
-	if (TryLockPage(page))
+	if (TestSetPageLocked(page))
 		return 0;
 
+	if (PageWriteback(page))
+		goto out_unlock;
+
 	/* From this point on, the odds are that we're going to
 	 * nuke this pte, so read and clear the pte.  This hook
 	 * is needed on CPUs which update the accessed and dirty
@@ -113,7 +122,7 @@
 		set_pte(page_table, swp_entry_to_pte(entry));
 drop_pte:
 		mm->rss--;
-		UnlockPage(page);
+		unlock_page(page);
 		{
 			int freeable = page_count(page) -
 				!!PagePrivate(page) <= 2;
@@ -180,7 +189,8 @@
 	/* No swap space left */
 preserve:
 	set_pte(page_table, pte);
-	UnlockPage(page);
+out_unlock:
+	unlock_page(page);
 	return 0;
 }
 
@@ -415,38 +425,61 @@
 		 * The page is locked. IO in progress?
 		 * Move it to the back of the list.
 		 */
-		if (unlikely(TryLockPage(page))) {
+		if (unlikely(PageWriteback(page))) {
 			if (PageLaunder(page) && (gfp_mask & __GFP_FS)) {
 				page_cache_get(page);
 				spin_unlock(&pagemap_lru_lock);
-				wait_on_page(page);
+				wait_on_page_writeback(page);
 				page_cache_release(page);
 				spin_lock(&pagemap_lru_lock);
 			}
 			continue;
 		}
 
+		if (TestSetPageLocked(page))
+			continue;
+
+		if (PageWriteback(page)) {	/* The non-racy check */
+			unlock_page(page);
+			continue;
+		}
+
 		mapping = page->mapping;
 
-		if (PageDirty(page) && is_page_cache_freeable(page) && mapping) {
+		if (PageDirty(page) && is_page_cache_freeable(page) &&
+				page->mapping && (gfp_mask & __GFP_FS)) {
 			/*
 			 * It is not critical here to write it only if
 			 * the page is unmapped beause any direct writer
-			 * like O_DIRECT would set the PG_dirty bitflag
+			 * like O_DIRECT would set the page's dirty bitflag
 			 * on the phisical page after having successfully
 			 * pinned it and after the I/O to the page is finished,
 			 * so the direct writes to the page cannot get lost.
 			 */
+			struct address_space_operations *a_ops;
+			int (*writeback)(struct page *, int *);
 			int (*writepage)(struct page *);
 
-			writepage = mapping->a_ops->writepage;
-			if ((gfp_mask & __GFP_FS) && writepage) {
-				ClearPageDirty(page);
+			/*
+			 * There's no guarantee that writeback() will actually
+			 * start I/O against *this* page.  Which is broken if we're
+			 * trying to free memory in a particular zone.  FIXME.
+			 */
+			a_ops = mapping->a_ops;
+			writeback = a_ops->vm_writeback;
+			writepage = a_ops->writepage;
+			if (writeback || writepage) {
 				SetPageLaunder(page);
 				page_cache_get(page);
 				spin_unlock(&pagemap_lru_lock);
+				ClearPageDirty(page);
 
-				writepage(page);
+				if (writeback) {
+					int nr_to_write = WRITEOUT_PAGES;
+					writeback(page, &nr_to_write);
+				} else {
+					writepage(page);
+				}
 				page_cache_release(page);
 
 				spin_lock(&pagemap_lru_lock);
@@ -474,7 +507,7 @@
 					 * taking the lru lock
 					 */
 					spin_lock(&pagemap_lru_lock);
-					UnlockPage(page);
+					unlock_page(page);
 					__lru_cache_del(page);
 
 					/* effectively free the page here */
@@ -495,7 +528,7 @@
 				}
 			} else {
 				/* failed to drop the buffers so stop here */
-				UnlockPage(page);
+				unlock_page(page);
 				page_cache_release(page);
 
 				spin_lock(&pagemap_lru_lock);
@@ -512,7 +545,7 @@
 				goto page_freeable;
 			write_unlock(&mapping->page_lock);
 		}
-		UnlockPage(page);
+		unlock_page(page);
 page_mapped:
 		if (--max_mapped >= 0)
 			continue;
@@ -532,7 +565,7 @@
 		 */
 		if (PageDirty(page)) {
 			write_unlock(&mapping->page_lock);
-			UnlockPage(page);
+			unlock_page(page);
 			continue;
 		}
 
@@ -549,7 +582,7 @@
 		}
 
 		__lru_cache_del(page);
-		UnlockPage(page);
+		unlock_page(page);
 
 		/* effectively free the page here */
 		page_cache_release(page);
@@ -581,7 +614,7 @@
 
 		page = list_entry(entry, struct page, lru);
 		entry = entry->prev;
-		if (PageTestandClearReferenced(page)) {
+		if (TestClearPageReferenced(page)) {
 			list_del(&page->lru);
 			list_add(&page->lru, &active_list);
 			continue;
diff -Nru a/sound/Makefile b/sound/Makefile
--- a/sound/Makefile	Tue Apr 30 17:10:25 2002
+++ b/sound/Makefile	Tue Apr 30 17:10:25 2002
@@ -5,48 +5,24 @@
 
 export-objs     := sound_core.o
 
+mod-subdirs	:= oss core i2c drivers isa pci ppc synth
+
 obj-$(CONFIG_SOUND) += soundcore.o
 
 subdir-$(CONFIG_SOUND_PRIME) += oss
-
 ifeq ($(CONFIG_SOUND_PRIME),y)
-  subdir-m += oss
-  obj-y += oss/sounddrivers.o
+  obj-y += oss/_oss.o
 endif
 
-_subdirs := core i2c drivers isa pci ppc arm synth
-
-subdir-$(CONFIG_SND) += $(_subdirs)
-
+subdir-$(CONFIG_SND) += core i2c drivers isa pci ppc arm synth
 ifeq ($(CONFIG_SND),y)
-  subdir-m += $(_subdirs)
-  obj-y += core/core.o i2c/_i2c.o
-  obj-y += drivers/drivers.o \
-	   drivers/mpu401/_mpu401.o \
-	   drivers/opl3/_opl3.o
-  obj-y += isa/isa.o \
-	   isa/ad1816a/_ad1816a.o \
-           isa/ad1848/_ad1848.o \
-	   isa/cs423x/_cs423x.o \
-	   isa/es1688/_es1688.o \
-	   isa/gus/_gus.o \
-	   isa/opti9xx/_opti9xx.o \
-	   isa/sb/_sb.o \
-	   isa/wavefront/_wavefront.o
-  obj-y += pci/pci.o \
-	   pci/ac97/_ac97.o \
-	   pci/ali5451/_ali5451.o \
-	   pci/cs46xx/_cs46xx.o \
-	   pci/emu10k1/_emu10k1.o \
-	   pci/korg1212/_korg1212.o \
-	   pci/nm256/_nm256.o \
-	   pci/rme9652/_rme9652.o \
-	   pci/trident/_trident.o \
-	   pci/ymfpci/_ymfpci.o
-  obj-y += ppc/ppc.o
-  obj-y += arm/arm.o
-  obj-y += synth/synth.o \
-	   synth/emux/_emux.o
+  obj-y += core/_core.o i2c/_i2c.o
+  obj-y += drivers/_drivers.o
+  obj-y += isa/_isa.o
+  obj-y += pci/_pci.o
+  obj-y += arm/_arm.o
+  obj-y += ppc/_ppc.o
+  obj-y += synth/_synth.o
   obj-y += last.o
 endif
 
diff -Nru a/sound/arm/Makefile b/sound/arm/Makefile
--- a/sound/arm/Makefile	Tue Apr 30 17:10:25 2002
+++ b/sound/arm/Makefile	Tue Apr 30 17:10:25 2002
@@ -2,7 +2,7 @@
 # Makefile for ALSA
 #
 
-O_TARGET    := arm.o
+O_TARGET    := _arm.o
 
 snd-sa11xx-uda1341-objs := sa11xx-uda1341.o
 
diff -Nru a/sound/core/Makefile b/sound/core/Makefile
--- a/sound/core/Makefile	Tue Apr 30 17:10:24 2002
+++ b/sound/core/Makefile	Tue Apr 30 17:10:24 2002
@@ -3,10 +3,12 @@
 # Copyright (c) 1999,2001 by Jaroslav Kysela <perex@suse.cz>
 #
 
-O_TARGET     := core.o
+O_TARGET     := _core.o
 
 export-objs  := sound.o pcm.o pcm_lib.o rawmidi.o timer.o rtctimer.o hwdep.o
 
+mod-subdirs  := oss seq
+
 snd-objs     := sound.o init.o isadma.o memory.o info.o control.o misc.o \
                 device.o wrappers.o
 ifeq ($(CONFIG_SND_OSSEMUL),y)
@@ -31,16 +33,14 @@
 subdir-$(CONFIG_SND_MIXER_OSS) += oss
 subdir-$(CONFIG_SND_PCM_OSS) += oss
 ifeq ($(filter $(subdir-y),oss),oss)
-  subdir-m += oss
-  obj-y += oss/oss.o
+  obj-y += oss/_oss.o
 endif
 
 obj-$(CONFIG_SND_PCM_OSS) += snd-pcm.o
 
 subdir-$(CONFIG_SND_SEQUENCER) += seq
 ifeq ($(CONFIG_SND_SEQUENCER),y)
-  subdir-m += seq
-  obj-y += seq/sq.o
+  obj-y += seq/_seq.o
 endif
 
 obj-$(CONFIG_SND_SEQUENCER) += snd-timer.o
diff -Nru a/sound/core/memory.c b/sound/core/memory.c
--- a/sound/core/memory.c	Tue Apr 30 17:10:23 2002
+++ b/sound/core/memory.c	Tue Apr 30 17:10:23 2002
@@ -26,6 +26,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/time.h>
+#include <linux/pci.h>
 #include <sound/core.h>
 #include <sound/info.h>
 
diff -Nru a/sound/core/oss/Makefile b/sound/core/oss/Makefile
--- a/sound/core/oss/Makefile	Tue Apr 30 17:10:23 2002
+++ b/sound/core/oss/Makefile	Tue Apr 30 17:10:23 2002
@@ -3,7 +3,7 @@
 # Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
 #
 
-O_TARGET     := oss.o
+O_TARGET     := _oss.o
 
 export-objs  := mixer_oss.o
 
diff -Nru a/sound/core/seq/Makefile b/sound/core/seq/Makefile
--- a/sound/core/seq/Makefile	Tue Apr 30 17:10:25 2002
+++ b/sound/core/seq/Makefile	Tue Apr 30 17:10:25 2002
@@ -3,14 +3,18 @@
 # Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
 #
 
-O_TARGET     := sq.o
+O_TARGET     := _seq.o
+
+mod-subdirs  := instr
+
+subdir-$(CONFIG_SND) += instr
+ifeq ($(CONFIG_SND),y)
+  obj-y        += instr/_instr.o
+endif
 
-subdir-y     := instr
-subdir-m     := $(subdir-y)
-obj-y        += instr/instr.o
 subdir-$(CONFIG_SND_SEQUENCER_OSS) += oss
 ifeq ($(CONFIG_SND_SEQUENCER_OSS),y)
-  obj-y	     += oss/oss.o
+  obj-y	     += oss/_oss.o
 endif
 
 export-objs  := seq_device.o seq.o seq_ports.o seq_instr.o seq_midi_emul.o \
diff -Nru a/sound/core/seq/instr/Makefile b/sound/core/seq/instr/Makefile
--- a/sound/core/seq/instr/Makefile	Tue Apr 30 17:10:25 2002
+++ b/sound/core/seq/instr/Makefile	Tue Apr 30 17:10:25 2002
@@ -3,7 +3,7 @@
 # Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
 #
 
-O_TARGET     := instr.o
+O_TARGET     := _instr.o
 
 export-objs  := ainstr_fm.o ainstr_simple.o ainstr_gf1.o ainstr_iw.o
 
diff -Nru a/sound/core/seq/oss/Makefile b/sound/core/seq/oss/Makefile
--- a/sound/core/seq/oss/Makefile	Tue Apr 30 17:10:25 2002
+++ b/sound/core/seq/oss/Makefile	Tue Apr 30 17:10:25 2002
@@ -3,7 +3,7 @@
 # Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
 #
 
-O_TARGET     := oss.o
+O_TARGET     := _oss.o
 
 snd-seq-oss-objs  := seq_oss.o seq_oss_init.o seq_oss_timer.o seq_oss_ioctl.o \
 		     seq_oss_event.o seq_oss_rw.o seq_oss_synth.o \
diff -Nru a/sound/core/seq/seq_dummy.c b/sound/core/seq/seq_dummy.c
--- a/sound/core/seq/seq_dummy.c	Tue Apr 30 17:10:25 2002
+++ b/sound/core/seq/seq_dummy.c	Tue Apr 30 17:10:25 2002
@@ -20,6 +20,7 @@
 
 #include <sound/driver.h>
 #include <linux/init.h>
+#include <linux/slab.h>
 #include <sound/core.h>
 #include "seq_clientmgr.h"
 #include <sound/initval.h>
diff -Nru a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c
--- a/sound/core/seq/seq_midi.c	Tue Apr 30 17:10:25 2002
+++ b/sound/core/seq/seq_midi.c	Tue Apr 30 17:10:25 2002
@@ -29,6 +29,8 @@
 #include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/errno.h>
+#include <asm/semaphore.h>
 #include <sound/core.h>
 #include <sound/rawmidi.h>
 #include <sound/seq_kernel.h>
diff -Nru a/sound/core/seq/seq_midi_event.c b/sound/core/seq/seq_midi_event.c
--- a/sound/core/seq/seq_midi_event.c	Tue Apr 30 17:10:23 2002
+++ b/sound/core/seq/seq_midi_event.c	Tue Apr 30 17:10:23 2002
@@ -21,6 +21,7 @@
 
 #include <sound/driver.h>
 #include <linux/slab.h>
+#include <linux/errno.h>
 #include <sound/core.h>
 #include <sound/seq_kernel.h>
 #include <sound/seq_midi_event.h>
diff -Nru a/sound/core/seq/seq_queue.h b/sound/core/seq/seq_queue.h
--- a/sound/core/seq/seq_queue.h	Tue Apr 30 17:10:25 2002
+++ b/sound/core/seq/seq_queue.h	Tue Apr 30 17:10:25 2002
@@ -51,7 +51,7 @@
 	spinlock_t check_lock;
 
 	/* clients which uses this queue (bitmap) */
-	unsigned int clients_bitmap[SNDRV_SEQ_MAX_CLIENTS/sizeof(unsigned int)];
+	unsigned int clients_bitmap[SNDRV_SEQ_MAX_CLIENTS/sizeof(unsigned long)];
 	unsigned int clients;	/* users of this queue */
 	struct semaphore timer_mutex;
 
diff -Nru a/sound/drivers/Makefile b/sound/drivers/Makefile
--- a/sound/drivers/Makefile	Tue Apr 30 17:10:25 2002
+++ b/sound/drivers/Makefile	Tue Apr 30 17:10:25 2002
@@ -3,10 +3,9 @@
 # Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
 #
 
-O_TARGET     := drivers.o
+O_TARGET     := _drivers.o
 
-subdir-y     := opl3 mpu401
-subdir-m     := $(subdir-y)
+mod-subdirs  := opl3 mpu401
 
 snd-dummy-objs := dummy.o
 snd-mtpav-objs := mtpav.o
@@ -18,5 +17,10 @@
 obj-$(CONFIG_SND_VIRMIDI) += snd-virmidi.o
 obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o
 obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o
+
+subdir-$(CONFIG_SND) += opl3 mpu401
+ifeq ($(CONFIG_SND),y)
+  obj-y += mpu401/_mpu401.o opl3/_opl3.o
+endif
 
 include $(TOPDIR)/Rules.make
diff -Nru a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c
--- a/sound/drivers/mpu401/mpu401_uart.c	Tue Apr 30 17:10:25 2002
+++ b/sound/drivers/mpu401/mpu401_uart.c	Tue Apr 30 17:10:25 2002
@@ -29,6 +29,8 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
 #include <sound/core.h>
 #include <sound/mpu401.h>
 
diff -Nru a/sound/isa/Makefile b/sound/isa/Makefile
--- a/sound/isa/Makefile	Tue Apr 30 17:10:25 2002
+++ b/sound/isa/Makefile	Tue Apr 30 17:10:25 2002
@@ -3,10 +3,9 @@
 # Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
 #
 
-O_TARGET     := isa.o
+O_TARGET     := _isa.o
 
-subdir-y     := ad1816a ad1848 cs423x es1688 gus opti9xx sb wavefront
-subdir-m     := $(subdir-y)
+mod-subdirs  := ad1816a ad1848 cs423x es1688 gus opti9xx sb wavefront
 
 snd-als100-objs := als100.o
 snd-azt2320-objs := azt2320.o
@@ -24,5 +23,17 @@
 obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o
 obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o
 obj-$(CONFIG_SND_SGALAXY) += snd-sgalaxy.o
+
+subdir-$(CONFIG_SND) += ad1816a ad1848 cs423x es1688 gus opti9xx sb wavefront
+ifeq ($(CONFIG_SND),y)
+  obj-y += ad1816a/_ad1816a.o \
+	   ad1848/_ad1848.o \
+	   cs423x/_cs423x.o \
+	   es1688/_es1688.o \
+	   gus/_gus.o \
+	   opti9xx/_opti9xx.o \
+	   sb/_sb.o \
+	   wavefront/_wavefront.o
+endif
 
 include $(TOPDIR)/Rules.make
diff -Nru a/sound/oss/Makefile b/sound/oss/Makefile
--- a/sound/oss/Makefile	Tue Apr 30 17:10:25 2002
+++ b/sound/oss/Makefile	Tue Apr 30 17:10:25 2002
@@ -3,6 +3,7 @@
 # 18 Apr 1998, Michael Elizabeth Chastain, <mailto:mec@shout.net>
 # Rewritten to use lists instead of if-statements.
 
+O_TARGET	:= _oss.o
 
 # All of the (potential) objects that export symbols.
 # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
@@ -81,17 +82,17 @@
 subdir-$(CONFIG_SOUND_CS4281) += cs4281
 
 ifeq ($(CONFIG_SOUND_EMU10K1),y)
-  obj-y += emu10k1/emu10k1.o
+  obj-y += emu10k1/_emu10k1.o
 endif
 
 ifeq ($(CONFIG_SOUND_CS4281),y)
-  obj-y += cs4281/cs4281.o
+  obj-y += cs4281/_cs4281.o
 endif
 
 subdir-$(CONFIG_DMASOUND) += dmasound
 
 ifeq ($(CONFIG_DMASOUND),y)
-  obj-y += dmasound/dmasound.o
+  obj-y += dmasound/_dmasound.o
 endif
 
 
@@ -110,8 +111,6 @@
 vidc_mod-objs	:= vidc.o vidc_fill.o
 wavefront-objs  := wavfront.o wf_midi.o yss225.o
 
-
-O_TARGET	:= sounddrivers.o
 
 include $(TOPDIR)/Rules.make
 
diff -Nru a/sound/oss/cs4281/Makefile b/sound/oss/cs4281/Makefile
--- a/sound/oss/cs4281/Makefile	Tue Apr 30 17:10:23 2002
+++ b/sound/oss/cs4281/Makefile	Tue Apr 30 17:10:23 2002
@@ -1,12 +1,10 @@
 # Makefile for Cirrus Logic-Crystal CS4281 
 #
 
-O_TARGET := cs4281.o
+O_TARGET := _cs4281.o
 
-obj-y := cs4281m.o
-obj-m := $(O_TARGET)
+obj-$(CONFIG_SOUND_CS4281) += cs4281.o
 
-include $(TOPDIR)/Rules.make
+cs4281-objs += cs4281m.o
 
-clean:
-	rm -f core *.o *.a *.s
+include $(TOPDIR)/Rules.make
diff -Nru a/sound/oss/dmasound/Makefile b/sound/oss/dmasound/Makefile
--- a/sound/oss/dmasound/Makefile	Tue Apr 30 17:10:25 2002
+++ b/sound/oss/dmasound/Makefile	Tue Apr 30 17:10:25 2002
@@ -7,15 +7,13 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
+O_TARGET = _dmasound.o
+
 export-objs := dmasound_core.o
 
 obj-$(CONFIG_DMASOUND_ATARI)  += dmasound_core.o dmasound_atari.o
 obj-$(CONFIG_DMASOUND_AWACS)  += dmasound_core.o dmasound_awacs.o
 obj-$(CONFIG_DMASOUND_PAULA)  += dmasound_core.o dmasound_paula.o
 obj-$(CONFIG_DMASOUND_Q40)    += dmasound_core.o dmasound_q40.o
-
-ifeq ($(CONFIG_DMASOUND),y)
-  O_TARGET = dmasound.o
-endif
 
 include $(TOPDIR)/Rules.make
diff -Nru a/sound/oss/emu10k1/Makefile b/sound/oss/emu10k1/Makefile
--- a/sound/oss/emu10k1/Makefile	Tue Apr 30 17:10:25 2002
+++ b/sound/oss/emu10k1/Makefile	Tue Apr 30 17:10:25 2002
@@ -2,12 +2,13 @@
 #
 # 12 Apr 2000 Rui Sousa
 
-O_TARGET := emu10k1.o
+O_TARGET := _emu10k1.o
 
-obj-y :=     audio.o cardmi.o cardmo.o cardwi.o cardwo.o ecard.o \
-             efxmgr.o emuadxmg.o hwaccess.o irqmgr.o main.o midi.o \
-             mixer.o passthrough.o recmgr.o timer.o voicemgr.o
-obj-m := $(O_TARGET)
+obj-$(CONFIG_SOUND_EMU10K1) += emu10k1.o
+
+emu10k1-objs := audio.o cardmi.o cardmo.o cardwi.o cardwo.o ecard.o \
+                efxmgr.o emuadxmg.o hwaccess.o irqmgr.o main.o midi.o \
+                mixer.o passthrough.o recmgr.o timer.o voicemgr.o
 
 ifdef DEBUG
     EXTRA_CFLAGS += -DEMU10K1_DEBUG
@@ -18,6 +19,3 @@
 endif
 
 include $(TOPDIR)/Rules.make
-
-clean:
-	rm -f core *.o *.a *.s
diff -Nru a/sound/oss/vidc_fill.S b/sound/oss/vidc_fill.S
--- a/sound/oss/vidc_fill.S	Tue Apr 30 17:10:25 2002
+++ b/sound/oss/vidc_fill.S	Tue Apr 30 17:10:25 2002
@@ -20,7 +20,7 @@
 ENTRY(vidc_fill_1x8_u)
 		mov	ip, #0xff00
 1:		cmp	r0, r1
-		bge	SYMBOL_NAME(vidc_clear)
+		bge	vidc_clear
 		ldrb	r4, [r0], #1
 		eor	r4, r4, #0x80
 		and	r4, ip, r4, lsl #8
@@ -33,7 +33,7 @@
 ENTRY(vidc_fill_2x8_u)
 		mov	ip, #0xff00
 1:		cmp	r0, r1
-		bge	SYMBOL_NAME(vidc_clear)
+		bge	vidc_clear
 		ldr	r4, [r0], #2
 		and	r5, r4, ip
 		and	r4, ip, r4, lsl #8
@@ -47,7 +47,7 @@
 ENTRY(vidc_fill_1x8_s)
 		mov	ip, #0xff00
 1:		cmp	r0, r1
-		bge	SYMBOL_NAME(vidc_clear)
+		bge	vidc_clear
 		ldrb	r4, [r0], #1
 		and	r4, ip, r4, lsl #8
 		orr	r4, r4, r4, lsl #16
@@ -59,7 +59,7 @@
 ENTRY(vidc_fill_2x8_s)
 		mov	ip, #0xff00
 1:		cmp	r0, r1
-		bge	SYMBOL_NAME(vidc_clear)
+		bge	vidc_clear
 		ldr	r4, [r0], #2
 		and	r5, r4, ip
 		and	r4, ip, r4, lsl #8
@@ -74,7 +74,7 @@
 		mov	ip, #0xff00
 		orr	ip, ip, ip, lsr #8
 1:		cmp	r0, r1
-		bge	SYMBOL_NAME(vidc_clear)
+		bge	vidc_clear
 		ldr	r5, [r0], #2
 		and	r4, r5, ip
 		orr	r4, r4, r4, lsl #16
@@ -92,7 +92,7 @@
 		mov	ip, #0xff00
 		orr	ip, ip, ip, lsr #8
 1:		cmp	r0, r1
-		bge	SYMBOL_NAME(vidc_clear)
+		bge	vidc_clear
 		ldr	r4, [r0], #4
 		str	r4, [r2], #4
 		cmp	r0, r1
@@ -136,10 +136,10 @@
 
 ENTRY(vidc_sound_dma_irq)
 		stmfd	sp!, {r4 - r8, lr}
-		ldr	r8, =SYMBOL_NAME(dma_start)
+		ldr	r8, =dma_start
 		ldmia	r8, {r0, r1, r2, r3, r4, r5}
 		teq	r1, #0
-		adreq	r4, SYMBOL_NAME(vidc_fill_noaudio)
+		adreq	r4, vidc_fill_noaudio
 		moveq	r7, #1 << 31
 		movne	r7, #0
 		mov	ip, #IOMD_BASE & 0xff000000
@@ -193,26 +193,26 @@
 		mov	pc, lr
 
 		.data
-		.globl	SYMBOL_NAME(dma_interrupt)
-SYMBOL_NAME(dma_interrupt):
+		.globl	dma_interrupt
+dma_interrupt:
 		.long	0				@ r3
-		.globl	SYMBOL_NAME(dma_pbuf)
-SYMBOL_NAME(dma_pbuf):
+		.globl	dma_pbuf
+dma_pbuf:
 		.long	0				@ r4
 		.long	0				@ r5
-		.globl	SYMBOL_NAME(dma_start)
-SYMBOL_NAME(dma_start):
+		.globl	dma_start
+dma_start:
 		.long	0				@ r0
-		.globl	SYMBOL_NAME(dma_count)
-SYMBOL_NAME(dma_count):
+		.globl	dma_count
+dma_count:
 		.long	0				@ r1
-		.globl	SYMBOL_NAME(dma_buf)
-SYMBOL_NAME(dma_buf):
+		.globl	dma_buf
+dma_buf:
 		.long	0				@ r2
 		.long	0				@ r3
-		.globl	SYMBOL_NAME(vidc_filler)
-SYMBOL_NAME(vidc_filler):
-		.long	SYMBOL_NAME(vidc_fill_noaudio)	@ r4
-		.globl	SYMBOL_NAME(dma_bufsize)
-SYMBOL_NAME(dma_bufsize):
+		.globl	vidc_filler
+vidc_filler:
+		.long	vidc_fill_noaudio		@ r4
+		.globl	dma_bufsize
+dma_bufsize:
 		.long	0x1000				@ r5
diff -Nru a/sound/pci/Makefile b/sound/pci/Makefile
--- a/sound/pci/Makefile	Tue Apr 30 17:10:23 2002
+++ b/sound/pci/Makefile	Tue Apr 30 17:10:23 2002
@@ -3,10 +3,9 @@
 # Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
 #
 
-O_TARGET     := pci.o
+O_TARGET     := _pci.o
 
-subdir-y     := ac97 ali5451 cs46xx emu10k1 korg1212 nm256 rme9652 trident ymfpci
-subdir-m     := $(subdir-y)
+mod-subdirs  := ac97 ali5451 cs46xx emu10k1 korg1212 nm256 rme9652 trident ymfpci
 
 snd-als4000-objs := als4000.o
 snd-cmipci-objs := cmipci.o
@@ -42,5 +41,18 @@
 obj-$(CONFIG_SND_SONICVIBES) += snd-sonicvibes.o
 obj-$(CONFIG_SND_VIA686) += snd-via686.o
 obj-$(CONFIG_SND_VIA8233) += snd-via8233.o
+
+subdir-$(CONFIG_SND) += ac97 ali5451 cs46xx emu10k1 korg1212 nm256 rme9652 trident ymfpci
+ifeq ($(CONFIG_SND),y)
+  obj-y += ac97/_ac97.o \
+	   ali5451/_ali5451.o \
+	   cs46xx/_cs46xx.o \
+	   emu10k1/_emu10k1.o \
+	   korg1212/_korg1212.o \
+	   nm256/_nm256.o \
+	   rme9652/_rme9652.o \
+	   trident/_trident.o \
+	   ymfpci/_ymfpci.o
+endif
 
 include $(TOPDIR)/Rules.make
diff -Nru a/sound/ppc/Makefile b/sound/ppc/Makefile
--- a/sound/ppc/Makefile	Tue Apr 30 17:10:25 2002
+++ b/sound/ppc/Makefile	Tue Apr 30 17:10:25 2002
@@ -3,7 +3,7 @@
 # Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
 #
 
-O_TARGET     := ppc.o
+O_TARGET     := _ppc.o
 
 snd-powermac-objs := powermac.o pmac.o awacs.o burgundy.o daca.o tumbler.o keywest.o
 
diff -Nru a/sound/synth/Makefile b/sound/synth/Makefile
--- a/sound/synth/Makefile	Tue Apr 30 17:10:23 2002
+++ b/sound/synth/Makefile	Tue Apr 30 17:10:23 2002
@@ -3,10 +3,9 @@
 # Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
 #
 
-O_TARGET     := synth.o
+O_TARGET     := _synth.o
 
-subdir-y     := emux
-subdir-m     := $(subdir-y)
+mod-subdirs  := emux
 
 export-objs  := util_mem.o
 
@@ -17,6 +16,11 @@
 obj-$(CONFIG_SND_TRIDENT) += snd-util-mem.o
 ifeq ($(subst m,y,$(CONFIG_SND_SEQUENCER)),y)
   obj-$(CONFIG_SND_SBAWE) += snd-util-mem.o
+endif
+
+subdir-$(CONFIG_SND) += emux
+ifeq ($(CONFIG_SND),y)
+  obj-y += emux/_emux.o
 endif
 
 include $(TOPDIR)/Rules.make
