## Automatically generated incremental diff
## From:   linux-2.4.11-pre2
## To:     linux-2.4.11-pre3
## Robot:  $Id: make-incremental-diff,v 1.8 2001/12/04 06:05:04 hpa Exp $

diff -urN linux-2.4.11-pre2/Makefile linux/Makefile
--- linux-2.4.11-pre2/Makefile	Mon Dec  3 23:15:29 2001
+++ linux/Makefile	Mon Dec  3 23:15:39 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 11
-EXTRAVERSION =-pre2
+EXTRAVERSION =-pre3
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.11-pre2/arch/ppc/mm/fault.c linux/arch/ppc/mm/fault.c
--- linux-2.4.11-pre2/arch/ppc/mm/fault.c	Mon Jul  2 14:34:57 2001
+++ linux/arch/ppc/mm/fault.c	Mon Dec  3 23:15:39 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.fault.c 1.13 06/28/01 15:50:17 paulus
+ * BK Id: SCCS/s.fault.c 1.15 09/24/01 16:35:10 paulus
  */
 /*
  *  arch/ppc/mm/fault.c
@@ -150,6 +150,7 @@
 	 * make sure we exit gracefully rather than endlessly redo
 	 * the fault.
 	 */
+ survive:
         switch (handle_mm_fault(mm, vma, address, is_write)) {
         case 1:
                 current->min_flt++;
@@ -195,6 +196,12 @@
  */
 out_of_memory:
 	up_read(&mm->mmap_sem);
+	if (current->pid == 1) {
+		current->policy |= SCHED_YIELD;
+		schedule();
+		down_read(&mm->mmap_sem);
+		goto survive;
+	}
 	printk("VM: killing process %s\n", current->comm);
 	if (user_mode(regs))
 		do_exit(SIGKILL);
@@ -346,34 +353,3 @@
         return(retval);
 }
 #endif /* CONFIG_8xx */
-
-#if 0
-/*
- * Misc debugging functions.  Please leave them here. -- Cort
- */
-void print_pte(struct _PTE p)
-{
-	printk(
-"%08x %08x vsid: %06x h: %01x api: %02x rpn: %05x rcwimg: %d%d%d%d%d%d pp: %02x\n",
-		*((unsigned long *)(&p)), *((long *)&p+1),
-		p.vsid, p.h, p.api, p.rpn,
-		p.r,p.c,p.w,p.i,p.m,p.g,p.pp);
-}
-
-/*
- * Search the hw hash table for a mapping to the given physical
- * address. -- Cort
- */
-unsigned long htab_phys_to_va(unsigned long address)
-{
-	extern PTE *Hash, *Hash_end;
-	PTE *ptr;
-
-	for ( ptr = Hash ; ptr < Hash_end ; ptr++ )
-	{
-		if ( ptr->rpn == (address>>12) )
-			printk("phys %08lX -> va ???\n",
-			       address);
-	}
-}
-#endif
diff -urN linux-2.4.11-pre2/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
--- linux-2.4.11-pre2/arch/ppc/mm/init.c	Tue Aug 28 06:58:33 2001
+++ linux/arch/ppc/mm/init.c	Mon Dec  3 23:15:39 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.init.c 1.34 08/20/01 22:12:43 paulus
+ * BK Id: SCCS/s.init.c 1.36 09/22/01 14:03:09 paulus
  */
 /*
  *  PowerPC version 
@@ -44,11 +44,14 @@
 #include <asm/smp.h>
 #include <asm/machdep.h>
 #include <asm/btext.h>
+#include <asm/tlb.h>
 
 #include "mem_pieces.h"
 #include "mmu_decl.h"
 
 #define MAX_LOW_MEM	(0xF0000000UL - KERNELBASE)
+
+mmu_gather_t mmu_gathers[NR_CPUS];
 
 void *end_of_DRAM;
 unsigned long total_memory;
diff -urN linux-2.4.11-pre2/arch/ppc/mm/mmu_context.c linux/arch/ppc/mm/mmu_context.c
--- linux-2.4.11-pre2/arch/ppc/mm/mmu_context.c	Tue Aug 28 06:58:33 2001
+++ linux/arch/ppc/mm/mmu_context.c	Mon Dec  3 23:15:39 2001
@@ -36,7 +36,7 @@
 #include <asm/mmu_context.h>
 
 mm_context_t next_mmu_context;
-unsigned long context_map[(LAST_CONTEXT+1) / (8*sizeof(unsigned long))];
+unsigned long context_map[LAST_CONTEXT / BITS_PER_LONG + 1];
 #ifdef FEW_CONTEXTS
 atomic_t nr_free_contexts;
 struct mm_struct *context_mm[LAST_CONTEXT+1];
@@ -57,7 +57,7 @@
 	context_map[0] = (1 << FIRST_CONTEXT) - 1;
 	next_mmu_context = FIRST_CONTEXT;
 #ifdef FEW_CONTEXTS
-	atomic_set(&nr_free_contexts, LAST_CONTEXT);
+	atomic_set(&nr_free_contexts, LAST_CONTEXT - FIRST_CONTEXT + 1);
 #endif /* FEW_CONTEXTS */
 }
 
diff -urN linux-2.4.11-pre2/arch/ppc/mm/pgtable.c linux/arch/ppc/mm/pgtable.c
--- linux-2.4.11-pre2/arch/ppc/mm/pgtable.c	Tue Aug 28 06:58:33 2001
+++ linux/arch/ppc/mm/pgtable.c	Mon Dec  3 23:15:39 2001
@@ -211,12 +211,12 @@
 #else
 		if ((char *) v < _stext || (char *) v >= etext)
 			f |= _PAGE_RW | _PAGE_DIRTY;
-#ifndef CONFIG_8xx
+#ifdef CONFIG_PPC_STD_MMU
 		else
-			/* On the powerpc (not 8xx), no user access
+			/* On the powerpc (not all), no user access
 			   forces R/W kernel access */
 			f |= _PAGE_USER;
-#endif /* CONFIG_8xx */
+#endif /* CONFIG_PPC_STD_MMU */
 #endif /* CONFIG_KGDB */
 		map_page(v, p, f);
 		v += PAGE_SIZE;
diff -urN linux-2.4.11-pre2/drivers/char/sysrq.c linux/drivers/char/sysrq.c
--- linux-2.4.11-pre2/drivers/char/sysrq.c	Mon Dec  3 23:15:29 2001
+++ linux/drivers/char/sysrq.c	Mon Dec  3 23:15:39 2001
@@ -231,12 +231,12 @@
 static void sysrq_handle_mountro(int key, struct pt_regs *pt_regs,
 		struct kbd_struct *kbd, struct tty_struct *tty) {
 	emergency_sync_scheduled = EMERG_REMOUNT;
-	wakeup_bdflush(0);
+	wakeup_bdflush();
 }
 static struct sysrq_key_op sysrq_mountro_op = {
 	handler:	sysrq_handle_mountro,
 	help_msg:	"Unmount",
-	action_msg:	"Emergency Remount R/0",
+	action_msg:	"Emergency Remount R/O",
 };
 
 /* END SYNC SYSRQ HANDLERS BLOCK */
diff -urN linux-2.4.11-pre2/drivers/ide/ide-pmac.c linux/drivers/ide/ide-pmac.c
--- linux-2.4.11-pre2/drivers/ide/ide-pmac.c	Sun Jul 15 16:22:23 2001
+++ linux/drivers/ide/ide-pmac.c	Mon Dec  3 23:15:39 2001
@@ -5,9 +5,7 @@
  * These IDE interfaces are memory-mapped and have a DBDMA channel
  * for doing DMA.
  *
- *  Copyright (C) 1998 Paul Mackerras.
- *
- *  Bits from Benjamin Herrenschmidt
+ *  Copyright (C) 1998-2001 Paul Mackerras & Ben. Herrenschmidt
  *
  *  This program is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU General Public License
@@ -99,13 +97,13 @@
 /* allow up to 256 DBDMA commands per xfer */
 #define MAX_DCMDS		256
 
-/* Wait 1.5s for disk to answer on IDE bus after
+/* Wait 2s for disk to answer on IDE bus after
  * enable operation.
  * NOTE: There is at least one case I know of a disk that needs about 10sec
  *       before anwering on the bus. I beleive we could add a kernel command
  *       line arg to override this delay for such cases.
  */
-#define IDE_WAKEUP_DELAY_MS	1500
+#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);
@@ -236,13 +234,21 @@
 	}
 	if((stat & ERR_STAT) || timeout <= 0) {
 		if (stat & ERR_STAT) {
-			printk("ide_pmace: wait_for_ready, error status: %x\n", stat);
+			printk(KERN_ERR "ide_pmac: wait_for_ready, error status: %x\n", stat);
 		}
 		return 1;
 	}
 	return 0;
 }
 
+/* Note: We don't use the generic routine here because some of Apple's
+ * controller seem to be very sensitive about how things are done.
+ * We should probably set the NIEN bit, but that's an example of thing
+ * that can cause the controller to hang under some circumstances when
+ * done on the media-bay CD-ROM during boot. We do get occasional
+ * spurrious interrupts because of that.
+ * --BenH
+ */
 static int
 pmac_ide_do_setfeature(ide_drive_t *drive, byte command)
 {
@@ -256,7 +262,7 @@
 	SELECT_MASK(HWIF(drive), drive, 0);
 	udelay(1);
 	if(wait_for_ready(drive)) {
-		printk("pmac_ide_do_setfeature disk not ready before SET_FEATURE!\n");
+		printk(KERN_ERR "pmac_ide_do_setfeature disk not ready before SET_FEATURE!\n");
 		goto out;
 	}
 	OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
@@ -265,7 +271,7 @@
 	udelay(1);
 	result = wait_for_ready(drive);
 	if (result)
-		printk("pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n");
+		printk(KERN_ERR "pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n");
 out:
 	restore_flags(flags);
 	
@@ -311,7 +317,7 @@
 	}
 
 #ifdef IDE_PMAC_DEBUG
-	printk("ide_pmac: Set PIO timing for mode %d, reg: 0x%08x\n",
+	printk(KERN_ERR "ide_pmac: Set PIO timing for mode %d, reg: 0x%08x\n",
 		pio,  *timings);
 #endif	
 		
@@ -562,7 +568,7 @@
 		   fixes in irq.c
 		 */
 		if (np->n_intrs == 0) {
-			printk("ide: no intrs for device %s, using 13\n",
+			printk(KERN_WARNING "ide: no intrs for device %s, using 13\n",
 			       np->full_name);
 			irq = 13;
 		} else {
@@ -598,7 +604,7 @@
 			 feature_set(np, FEATURE_IDE0_enable);
 		} else {
  			/* This is necessary to enable IDE when net-booting */
-			printk("pmac_ide: enabling IDE bus ID %d\n",
+			printk(KERN_INFO "pmac_ide: enabling IDE bus ID %d\n",
 				pmac_ide[i].aapl_bus_id);
 			switch(pmac_ide[i].aapl_bus_id) {
 			    case 0:
@@ -732,7 +738,7 @@
 			unsigned int tc = (size < 0xfe00)? size: 0xfe00;
 
 			if (++count >= MAX_DCMDS) {
-				printk("%s: DMA table too small\n",
+				printk(KERN_WARNING "%s: DMA table too small\n",
 				       drive->name);
 				return 0; /* revert to PIO for this request */
 			}
@@ -804,10 +810,10 @@
 	int ret;
 
 	/* Set feature on drive */
-    	printk("%s: Enabling MultiWord DMA %d\n", drive->name, feature & 0xf);
+    	printk(KERN_INFO "%s: Enabling MultiWord DMA %d\n", drive->name, feature & 0xf);
 	ret = pmac_ide_do_setfeature(drive, feature);
 	if (ret) {
-	    	printk("%s: Failed !\n", drive->name);
+	    	printk(KERN_WARNING "%s: Failed !\n", drive->name);
 	    	return 0;
 	}
 
@@ -860,7 +866,7 @@
 			(accessTicks | (recTicks << 5) | (halfTick << 10)) << 11;
 	}
 #ifdef IDE_PMAC_DEBUG
-	printk("ide_pmac: Set MDMA timing for mode %d, reg: 0x%08x\n",
+	printk(KERN_INFO "ide_pmac: Set MDMA timing for mode %d, reg: 0x%08x\n",
 		feature & 0xf, *timings);
 #endif
 	drive->current_speed = feature;	
@@ -879,10 +885,10 @@
 	int ret;
 
 	/* Set feature on drive */
-    	printk("%s: Enabling Ultra DMA %d\n", drive->name, feature & 0xf);
+    	printk(KERN_INFO "%s: Enabling Ultra DMA %d\n", drive->name, feature & 0xf);
 	ret = pmac_ide_do_setfeature(drive, feature);
 	if (ret) {
-		printk("%s: Failed !\n", drive->name);
+		printk(KERN_WARNING "%s: Failed !\n", drive->name);
 		return 0;
 	}
 
@@ -953,7 +959,7 @@
 
 int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
 {
-	int ix, dstat;
+	int ix, dstat, i;
 	volatile struct dbdma_regs *dma;
 
 	/* Can we stuff a pointer to our intf structure in config_data
@@ -966,7 +972,7 @@
 
 	switch (func) {
 	case ide_dma_off:
-		printk("%s: DMA disabled\n", drive->name);
+		printk(KERN_INFO "%s: DMA disabled\n", drive->name);
 	case ide_dma_off_quietly:
 		drive->using_dma = 0;
 		break;
@@ -994,7 +1000,27 @@
 		/* verify good dma status */
 		return (dstat & (RUN|DEAD|ACTIVE)) != RUN;
 	case ide_dma_test_irq:
-		return (in_le32(&dma->status) & (RUN|ACTIVE)) == RUN;
+		if ((in_le32(&dma->status) & (RUN|ACTIVE)) == RUN)
+			return 1;
+		/* That's a bit ugly and dangerous, but works in our case
+		 * to workaround a problem with the channel status staying
+		 * active if the drive returns an error
+		 */
+		if (IDE_CONTROL_REG) {
+			byte stat;
+			stat = GET_ALTSTAT();
+			if (stat & ERR_STAT)
+				return 1;
+		}
+		/* In some edge cases, some datas may still be in the dbdma
+		 * engine fifo, we wait a bit for dbdma to complete
+		 */
+		while ((in_le32(&dma->status) & (RUN|ACTIVE)) != RUN) {
+			if (++i > 100)
+				return 0;
+			udelay(1);
+		}
+		return 1;
 
 		/* Let's implement tose just in case someone wants them */
 	case ide_dma_bad_drive:
@@ -1005,10 +1031,10 @@
 	case ide_dma_retune:
 	case ide_dma_lostirq:
 	case ide_dma_timeout:
-		printk("ide_pmac_dmaproc: chipset supported %s func only: %d\n", ide_dmafunc_verbose(func),  func);
+		printk(KERN_WARNING "ide_pmac_dmaproc: chipset supported %s func only: %d\n", ide_dmafunc_verbose(func),  func);
 		return 1;
 	default:
-		printk("ide_pmac_dmaproc: unsupported %s func: %d\n", ide_dmafunc_verbose(func), func);
+		printk(KERN_WARNING "ide_pmac_dmaproc: unsupported %s func: %d\n", ide_dmafunc_verbose(func), func);
 		return 1;
 	}
 	return 0;
@@ -1016,13 +1042,15 @@
 #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
 
 #ifdef CONFIG_PMAC_PBOOK
-static void idepmac_sleep_disk(int i, unsigned long base)
+static void idepmac_sleep_device(ide_drive_t *drive, int i, unsigned base)
 {
-	struct device_node* np = pmac_ide[i].node;
 	int j;
-
-	/* FIXME: We only handle the master IDE */
-	if (ide_hwifs[i].drives[0].media == ide_disk) {
+	
+	/* FIXME: We only handle the master IDE disk, we shoud
+	 *        try to fix CD-ROMs here
+	 */
+	switch (drive->media) {
+	case ide_disk:
 		/* Spin down the drive */
 		outb(0xa0, base+0x60);
 		outb(0x0, base+0x30);
@@ -1038,86 +1066,112 @@
 			if (!(status & BUSY_STAT) && (status & DRQ_STAT))
 				break;
 		}
-	}
-	feature_set(np, FEATURE_IDE0_reset);
-	feature_clear(np, FEATURE_IDE0_enable);
-	switch(pmac_ide[i].aapl_bus_id) {
-	    case 0:
-		feature_set(np, FEATURE_IDE0_reset);
-		feature_clear(np, FEATURE_IDE0_enable);
 		break;
-	    case 1:
-		feature_set(np, FEATURE_IDE1_reset);
-		feature_clear(np, FEATURE_IDE1_enable);
+	case ide_cdrom:
+		// todo
 		break;
-	    case 2:
-		feature_set(np, FEATURE_IDE2_reset);
+	case ide_floppy:
+		// todo
 		break;
 	}
-	pmac_ide[i].timings[0] = 0;
-	pmac_ide[i].timings[1] = 0;
 }
 
-static void idepmac_wake_disk(int i, unsigned long base)
+static void idepmac_wake_device(ide_drive_t *drive, int used_dma)
+ {
+	/* We force the IDE subdriver to check for a media change
+	 * This must be done first or we may lost the condition
+	 *
+	 * Problem: This can schedule. I moved the block device
+	 * wakeup almost late by priority because of that.
+	 */
+	if (DRIVER(drive) && DRIVER(drive)->media_change)
+		DRIVER(drive)->media_change(drive);
+
+	/* We kick the VFS too (see fix in ide.c revalidate) */
+	check_disk_change(MKDEV(HWIF(drive)->major, (drive->select.b.unit) << PARTN_BITS));
+	
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+	/* We re-enable DMA on the drive if it was active. */
+	/* This doesn't work with the CD-ROM in the media-bay, probably
+	 * because of a pending unit attention. The problem if that if I
+	 * clear the error, the filesystem dies.
+	 */
+	if (used_dma && !ide_spin_wait_hwgroup(drive)) {
+		/* Lock HW group */
+		HWGROUP(drive)->busy = 1;
+		pmac_ide_check_dma(drive);
+		HWGROUP(drive)->busy = 0;
+		spin_unlock_irq(&io_request_lock);
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+}
+
+static void idepmac_sleep_interface(int i, unsigned base, int mediabay)
 {
 	struct device_node* np = pmac_ide[i].node;
-	int j;
 
-	/* Revive IDE disk and controller */
+	/* We clear the timings */
+	pmac_ide[i].timings[0] = 0;
+	pmac_ide[i].timings[1] = 0;
+	
+	/* The media bay will handle itself just fine */
+	if (mediabay)
+		return;
+	
+	/* Disable and reset the bus */
+	feature_set(np, FEATURE_IDE0_reset);
+	feature_clear(np, FEATURE_IDE0_enable);
 	switch(pmac_ide[i].aapl_bus_id) {
 	    case 0:
 		feature_set(np, FEATURE_IDE0_reset);
-		mdelay(10);
- 		feature_set(np, FEATURE_IDE0_enable);
-		mdelay(10);
-		feature_clear(np, FEATURE_IDE0_reset);
+		feature_clear(np, FEATURE_IDE0_enable);
 		break;
 	    case 1:
 		feature_set(np, FEATURE_IDE1_reset);
-		mdelay(10);
- 		feature_set(np, FEATURE_IDE1_enable);
-		mdelay(10);
-		feature_clear(np, FEATURE_IDE1_reset);
+		feature_clear(np, FEATURE_IDE1_enable);
 		break;
 	    case 2:
-	    	/* This one exists only for KL, I don't know
-		   about any enable bit */
 		feature_set(np, FEATURE_IDE2_reset);
-		mdelay(10);
-		feature_clear(np, FEATURE_IDE2_reset);
 		break;
 	}
-	mdelay(IDE_WAKEUP_DELAY_MS);
-
-	/* Reset timings */
-	pmac_ide_selectproc(&ide_hwifs[i].drives[0]);
-	mdelay(10);
-
-	/* Wait up to 10 seconds (enough for recent drives) */
-	for (j = 0; j < 100; j++) {
-		int status;
-		mdelay(100);
-		status = inb(base + 0x70);
-		if (!(status & BUSY_STAT))
-			break;
-	}
 }
 
-/* Here we handle media bay devices */
-static void
-idepmac_wake_bay(int i, unsigned long base)
+static void idepmac_wake_interface(int i, unsigned long base, int mediabay)
 {
-	int timeout;
+	struct device_node* np = pmac_ide[i].node;
 
+	if (!mediabay) {
+		/* Revive IDE disk and controller */
+		switch(pmac_ide[i].aapl_bus_id) {
+		    case 0:
+			feature_set(np, FEATURE_IDE0_reset);
+			feature_set(np, FEATURE_IOBUS_enable);
+			mdelay(10);
+	 		feature_set(np, FEATURE_IDE0_enable);
+			mdelay(10);
+			feature_clear(np, FEATURE_IDE0_reset);
+			break;
+		    case 1:
+			feature_set(np, FEATURE_IDE1_reset);
+			feature_set(np, FEATURE_IOBUS_enable);
+			mdelay(10);
+	 		feature_set(np, FEATURE_IDE1_enable);
+			mdelay(10);
+			feature_clear(np, FEATURE_IDE1_reset);
+			break;
+		    case 2:
+		    	/* This one exists only for KL, I don't know
+			   about any enable bit */
+			feature_set(np, FEATURE_IDE2_reset);
+			mdelay(10);
+			feature_clear(np, FEATURE_IDE2_reset);
+			break;
+		}
+	}
+	
 	/* Reset timings */
 	pmac_ide_selectproc(&ide_hwifs[i].drives[0]);
 	mdelay(10);
-
-	timeout = 10000;
-	while ((inb(base + 0x70) & BUSY_STAT) && timeout) {
-		mdelay(1);
-		--timeout;
-	}
 }
 
 /* Note: We support only master drives for now. This will have to be
@@ -1128,6 +1182,8 @@
 {
 	int i, ret;
 	unsigned long base;
+	unsigned long flags;
+	int big_delay;
 
 	switch (when) {
 	case PBOOK_SLEEP_REQUEST:
@@ -1136,34 +1192,104 @@
 		break;
 	case PBOOK_SLEEP_NOW:
 		for (i = 0; i < pmac_ide_count; ++i) {
+			ide_hwif_t *hwif;
+			ide_drive_t *drive;
+			int unlock = 0;
+
 			if ((base = pmac_ide[i].regbase) == 0)
-				continue;
+				continue;	
+
+			hwif = &ide_hwifs[i];
+			drive = &hwif->drives[0];
+			
+			if (drive->present) {
+				/* Wait for HW group to complete operations */
+				if (ide_spin_wait_hwgroup(drive)) {
+					// What can we do here ? Wake drive we had already
+					// put to sleep and return an error ?
+				} else {
+					unlock = 1;
+					/* Lock HW group */
+					HWGROUP(drive)->busy = 1;
+
+					/* Stop the device */
+					idepmac_sleep_device(drive, i, base);
+				
+				}
+			}
 			/* Disable irq during sleep */
 			disable_irq(pmac_ide[i].irq);
+			if (unlock)
+				spin_unlock_irq(&io_request_lock);
+			
+			/* Check if this is a media bay with an IDE device or not
+			 * a media bay.
+			 */
 			ret = check_media_bay_by_base(base, MB_CD);
-			if ((ret == -ENODEV) && ide_hwifs[i].drives[0].present)
-				/* not media bay - put the disk to sleep */
-				idepmac_sleep_disk(i, base);
+			if ((ret == 0) || (ret == -ENODEV))
+				idepmac_sleep_interface(i, base, (ret == 0));
 		}
 		break;
 	case PBOOK_WAKE:
+		big_delay = 0;
+		for (i = 0; i < pmac_ide_count; ++i) {
+
+			if ((base = pmac_ide[i].regbase) == 0)
+				continue;
+				
+			/* Check if this is a media bay with an IDE device or not
+			 * a media bay
+			 */
+			ret = check_media_bay_by_base(base, MB_CD);
+			if ((ret == 0) || (ret == -ENODEV)) {
+				idepmac_wake_interface(i, base, (ret == 0));				
+				big_delay = 1;
+			}
+
+		}
+		/* Let hardware get up to speed */
+		if (big_delay)
+			mdelay(IDE_WAKEUP_DELAY_MS);
+	
 		for (i = 0; i < pmac_ide_count; ++i) {
 			ide_hwif_t *hwif;
+			ide_drive_t *drive;			
+			int j, used_dma;
+			
 			if ((base = pmac_ide[i].regbase) == 0)
 				continue;
+				
 			hwif = &ide_hwifs[i];
-		        /* We don't handle media bay devices this way */
-			ret = check_media_bay_by_base(base, MB_CD);
-			if ((ret == -ENODEV) && ide_hwifs[i].drives[0].present)
-				idepmac_wake_disk(i, base);
-			else if (ret == 0)
-				idepmac_wake_bay(i, base);
-			enable_irq(pmac_ide[i].irq);
+			drive = &hwif->drives[0];
 
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-			if (hwif->drives[0].present && hwif->drives[0].using_dma)
-				pmac_ide_check_dma(&hwif->drives[0]);
-#endif				
+			/* Wait for the drive to come up and set it's DMA */
+			if (drive->present) {
+				/* Wait up to 20 seconds */
+				for (j = 0; j < 200; j++) {
+					int status;
+					mdelay(100);
+					status = inb(base + 0x70);
+					if (!(status & BUSY_STAT))
+						break;
+				}
+			}
+			
+			/* We don't have re-configured DMA yet */
+			used_dma = drive->using_dma;
+			drive->using_dma = 0;
+
+			/* We resume processing on the HW group */
+			spin_lock_irqsave(&io_request_lock, flags);
+			enable_irq(pmac_ide[i].irq);
+			if (drive->present)
+				HWGROUP(drive)->busy = 0;
+			spin_unlock_irqrestore(&io_request_lock, flags);
+			
+			/* Wake the device
+			 * We could handle the slave here
+			 */
+			if (drive->present)
+				idepmac_wake_device(drive, used_dma);
 		}
 		break;
 	}
diff -urN linux-2.4.11-pre2/drivers/ieee1394/highlevel.c linux/drivers/ieee1394/highlevel.c
--- linux-2.4.11-pre2/drivers/ieee1394/highlevel.c	Fri Sep  7 09:28:38 2001
+++ linux/drivers/ieee1394/highlevel.c	Mon Dec  3 23:15:39 2001
@@ -154,21 +154,18 @@
 }
 
 
-#define DEFINE_MULTIPLEXER(Function) \
-void highlevel_##Function(struct hpsb_host *host) \
-{ \
-        struct list_head *entry,*next; \
-        void (*funcptr)(struct hpsb_host*); \
-        read_lock(&hl_drivers_lock); \
-        entry = hl_drivers.next; \
-        while (entry != &hl_drivers) { \
-        	next = entry->next; \
-                funcptr = list_entry(entry, struct hpsb_highlevel, hl_list) \
-                          ->op->Function; \
-                if (funcptr) funcptr(host); \
-                entry = next; \
-        } \
-        read_unlock(&hl_drivers_lock); \
+#define DEFINE_MULTIPLEXER(Function)			\
+void highlevel_##Function(struct hpsb_host *host)	\
+{							\
+	struct list_head *lh;				\
+	void (*funcptr)(struct hpsb_host*);		\
+	read_lock(&hl_drivers_lock);			\
+	list_for_each(lh, &hl_drivers) {		\
+		funcptr = list_entry(lh, struct hpsb_highlevel, hl_list) \
+				->op->Function;		\
+		if (funcptr) funcptr(host);		\
+	}						\
+	read_unlock(&hl_drivers_lock);			\
 }
 
 DEFINE_MULTIPLEXER(add_host)
diff -urN linux-2.4.11-pre2/drivers/ieee1394/hosts.c linux/drivers/ieee1394/hosts.c
--- linux-2.4.11-pre2/drivers/ieee1394/hosts.c	Sun Aug 12 12:39:02 2001
+++ linux/drivers/ieee1394/hosts.c	Mon Dec  3 23:15:39 2001
@@ -23,8 +23,8 @@
 #include "highlevel.h"
 
 
-static struct hpsb_host_template *templates = NULL;
-spinlock_t templates_lock = SPIN_LOCK_UNLOCKED;
+static LIST_HEAD(templates);
+static spinlock_t templates_lock = SPIN_LOCK_UNLOCKED;
 
 /*
  * This function calls the add_host/remove_host hooks for every host currently
@@ -32,13 +32,16 @@
  */
 void hl_all_hosts(struct hpsb_highlevel *hl, int init)
 {
+	struct list_head *tlh, *hlh;
         struct hpsb_host_template *tmpl;
         struct hpsb_host *host;
 
         spin_lock(&templates_lock);
 
-        for (tmpl = templates; tmpl != NULL; tmpl = tmpl->next) {
-                for (host = tmpl->hosts; host != NULL; host = host->next) {
+	list_for_each(tlh, &templates) {
+                tmpl = list_entry(tlh, struct hpsb_host_template, list);
+		list_for_each(hlh, &tmpl->hosts) {
+			host = list_entry(hlh, struct hpsb_host, list);
                         if (host->initialized) {
                                 if (init) {
                                         if (hl->op->add_host) {
@@ -58,21 +61,24 @@
 
 int hpsb_inc_host_usage(struct hpsb_host *host)
 {
+	struct list_head *tlh, *hlh;
         struct hpsb_host_template *tmpl;
-        struct hpsb_host *h;
         int retval = 0;
 	unsigned long flags;
 
         spin_lock_irqsave(&templates_lock, flags);
 
-        for (tmpl = templates; (tmpl != NULL) && !retval; tmpl = tmpl->next) {
-                for (h = tmpl->hosts; h != NULL; h = h->next) {
-                        if (h == host) {
-                                tmpl->devctl(h, MODIFY_USAGE, 1);
+	list_for_each(tlh, &templates) {
+                tmpl = list_entry(tlh, struct hpsb_host_template, list);
+		list_for_each(hlh, &tmpl->hosts) {
+			if (host == list_entry(hlh, struct hpsb_host, list)) {
+                                tmpl->devctl(host, MODIFY_USAGE, 1);
                                 retval = 1;
                                 break;
                         }
                 }
+		if (retval)
+			break;
         }
 
         spin_unlock_irqrestore(&templates_lock, flags);
@@ -113,32 +119,22 @@
         h->speed_map = (u8 *)(h->csr.speed_map + 2);
 
         h->template = tmpl;
-        if (hd_size) {
+        if (hd_size)
                 h->hostdata = &h->embedded_hostdata[0];
-        }
-
-        if (tmpl->hosts == NULL) {
-                tmpl->hosts = h;
-        } else {
-                struct hpsb_host *last = tmpl->hosts;
 
-                while (last->next != NULL) {
-                        last = last->next;
-                }
-                last->next = h;
-        }
+	list_add_tail(&h->list, &tmpl->hosts);
 
         return h;
 }
 
 static void free_all_hosts(struct hpsb_host_template *tmpl)
 {
-        struct hpsb_host *next, *host = tmpl->hosts;
+	struct list_head *hlh, *next;
+        struct hpsb_host *host;
 
-        while (host) {
-                next = host->next;
+	list_for_each_safe(hlh, next, &tmpl->hosts) {
+		host = list_entry(hlh, struct hpsb_host, list);
                 vfree(host);
-                host = next;
         }
 }
 
@@ -146,11 +142,13 @@
 static void init_hosts(struct hpsb_host_template *tmpl)
 {
         int count;
+	struct list_head *hlh;
         struct hpsb_host *host;
 
         count = tmpl->detect_hosts(tmpl);
 
-        for (host = tmpl->hosts; host != NULL; host = host->next) {
+	list_for_each(hlh, &tmpl->hosts) {
+		host = list_entry(hlh, struct hpsb_host, list);
                 if (tmpl->initialize_host(host)) {
                         host->initialized = 1;
 
@@ -166,9 +164,11 @@
 
 static void shutdown_hosts(struct hpsb_host_template *tmpl)
 {
+	struct list_head *hlh;
         struct hpsb_host *host;
 
-        for (host = tmpl->hosts; host != NULL; host = host->next) {
+	list_for_each(hlh, &tmpl->hosts) {
+		host = list_entry(hlh, struct hpsb_host, list);
                 if (host->initialized) {
                         host->initialized = 0;
                         abort_requests(host);
@@ -188,68 +188,17 @@
 }
 
 
-static int add_template(struct hpsb_host_template *new)
-{
-        new->next = NULL;
-        new->hosts = NULL;
-        new->number_of_hosts = 0;
-
-        spin_lock(&templates_lock);
-        if (templates == NULL) {
-                templates = new;
-        } else {
-                struct hpsb_host_template *last = templates;
-                while (last->next != NULL) {
-                        last = last->next;
-                }
-                last->next = new;
-        }
-        spin_unlock(&templates_lock);
-
-        return 0;
-}
-
-static int remove_template(struct hpsb_host_template *tmpl)
-{
-        int retval = 0;
-
-        if (tmpl->number_of_hosts) {
-                HPSB_ERR("attempted to remove busy host template "
-                         "of %s at address 0x%p", tmpl->name, tmpl);
-                return 1;
-        }
-
-        spin_lock(&templates_lock);
-        if (templates == tmpl) {
-                templates = tmpl->next;
-        } else {
-                struct hpsb_host_template *t;
-
-                t = templates;
-                while (t->next != tmpl && t->next != NULL) {
-                        t = t->next;
-                }
-
-                if (t->next == NULL) {
-                        HPSB_ERR("attempted to remove unregistered host template "
-                                 "of %s at address 0x%p", tmpl->name, tmpl);
-                        retval = -1;
-                } else {
-                        t->next = tmpl->next;
-                }
-        }
-        spin_unlock(&templates_lock);
-
-        return retval;
-}
-
-
 /*
  * The following two functions are exported symbols for module usage.
  */
 int hpsb_register_lowlevel(struct hpsb_host_template *tmpl)
 {
-        add_template(tmpl);
+	INIT_LIST_HEAD(&tmpl->hosts);
+	tmpl->number_of_hosts = 0;
+
+        spin_lock(&templates_lock);
+	list_add_tail(&tmpl->list, &templates);
+        spin_unlock(&templates_lock);
 
 	/* PCI cards should be smart and use the PCI detection layer, and
 	 * not this one shot deal. detect_hosts() will be obsoleted soon. */
@@ -265,7 +214,12 @@
 {
         shutdown_hosts(tmpl);
 
-        if (remove_template(tmpl)) {
-                HPSB_PANIC("remove_template failed on %s", tmpl->name);
-        }
+        if (tmpl->number_of_hosts)
+                HPSB_PANIC("attempted to remove busy host template "
+			   "of %s at address 0x%p", tmpl->name, tmpl);
+	else {
+		spin_lock(&templates_lock);
+		list_del(&tmpl->list);
+		spin_unlock(&templates_lock);
+	}
 }
diff -urN linux-2.4.11-pre2/drivers/ieee1394/hosts.h linux/drivers/ieee1394/hosts.h
--- linux-2.4.11-pre2/drivers/ieee1394/hosts.h	Sun Aug 12 12:39:02 2001
+++ linux/drivers/ieee1394/hosts.h	Mon Dec  3 23:15:39 2001
@@ -3,6 +3,7 @@
 
 #include <linux/wait.h>
 #include <linux/tqueue.h>
+#include <linux/list.h>
 #include <asm/semaphore.h>
 
 #include "ieee1394_types.h"
@@ -13,7 +14,7 @@
 
 struct hpsb_host {
 /* private fields (hosts, do not use them) */
-        struct hpsb_host *next;
+	struct list_head list;
 
         atomic_t generation;
 
@@ -109,9 +110,9 @@
 };
 
 struct hpsb_host_template {
-        struct hpsb_host_template *next;
+	struct list_head list;
 
-        struct hpsb_host *hosts;
+        struct list_head hosts;
         int number_of_hosts;
 
         /* fields above will be ignored and overwritten after registering */
diff -urN linux-2.4.11-pre2/drivers/ieee1394/ieee1394_core.c linux/drivers/ieee1394/ieee1394_core.c
--- linux-2.4.11-pre2/drivers/ieee1394/ieee1394_core.c	Fri Sep  7 09:28:38 2001
+++ linux/drivers/ieee1394/ieee1394_core.c	Mon Dec  3 23:15:39 2001
@@ -17,6 +17,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
+#include <linux/module.h>
 #include <asm/bitops.h>
 #include <asm/byteorder.h>
 #include <asm/semaphore.h>
@@ -30,6 +31,13 @@
 #include "csr.h"
 #include "nodemgr.h"
 
+/*
+ * Disable the nodemgr detection and config rom reading functionality.
+ */
+MODULE_PARM(disable_nodemgr, "i");
+MODULE_PARM_DESC(disable_nodemgr, "Disable nodemgr functionality.");
+static int disable_nodemgr = 0;
+
 static kmem_cache_t *hpsb_packet_cache;
 
 
@@ -95,7 +103,7 @@
         INIT_TQ_HEAD(packet->complete_tq);
         INIT_LIST_HEAD(&packet->list);
         sema_init(&packet->state_change, 0);
-        packet->state = unused;
+        packet->state = hpsb_unused;
         packet->generation = -1;
         packet->data_be = 1;
 
@@ -352,14 +360,14 @@
         }
 
         if (ackcode != ACK_PENDING || !packet->expect_response) {
-                packet->state = completed;
+                packet->state = hpsb_complete;
                 up(&packet->state_change);
                 up(&packet->state_change);
                 run_task_queue(&packet->complete_tq);
                 return;
         }
 
-        packet->state = pending;
+        packet->state = hpsb_pending;
         packet->sendtime = jiffies;
 
         spin_lock_irqsave(&host->pending_pkt_lock, flags);
@@ -393,9 +401,9 @@
                 return 0;
         }
 
-        packet->state = queued;
+        packet->state = hpsb_queued;
 
-        if (packet->type == async && packet->node_id != ALL_NODES) {
+        if (packet->type == hpsb_async && packet->node_id != ALL_NODES) {
                 packet->speed_code =
                         host->speed_map[(host->node_id & NODE_MASK) * 64
                                        + (packet->node_id & NODE_MASK)];
@@ -503,14 +511,14 @@
                 break;
         }
 
-        packet->state = completed;
+        packet->state = hpsb_complete;
         up(&packet->state_change);
         run_task_queue(&packet->complete_tq);
 }
 
 
-struct hpsb_packet *create_reply_packet(struct hpsb_host *host, quadlet_t *data,
-                                        size_t dsize)
+static struct hpsb_packet *create_reply_packet(struct hpsb_host *host,
+					       quadlet_t *data, size_t dsize)
 {
         struct hpsb_packet *p;
 
@@ -522,13 +530,15 @@
                 return NULL;
         }
 
-        p->type = async;
-        p->state = unused;
+        p->type = hpsb_async;
+        p->state = hpsb_unused;
         p->host = host;
         p->node_id = data[1] >> 16;
         p->tlabel = (data[0] >> 10) & 0x3f;
         p->no_waiter = 1;
 
+	p->generation = get_hpsb_generation(host);
+
         if (dsize % 4) {
                 p->data[dsize / 4] = 0;
         }
@@ -540,8 +550,8 @@
                 packet = create_reply_packet(host, data, length); \
                 if (packet == NULL) break
 
-void handle_incoming_packet(struct hpsb_host *host, int tcode, quadlet_t *data,
-                            size_t size, int write_acked)
+static void handle_incoming_packet(struct hpsb_host *host, int tcode,
+				   quadlet_t *data, size_t size, int write_acked)
 {
         struct hpsb_packet *packet;
         int length, rcode, extcode;
@@ -720,7 +730,7 @@
 
         list_for_each(lh, &llist) {
                 packet = list_entry(lh, struct hpsb_packet, list);
-                packet->state = completed;
+                packet->state = hpsb_complete;
                 packet->ack_code = ACKX_ABORTED;
                 up(&packet->state_change);
                 run_task_queue(&packet->complete_tq);
@@ -732,7 +742,7 @@
         unsigned long flags;
         struct hpsb_packet *packet;
         unsigned long expire;
-        struct list_head *lh;
+        struct list_head *lh, *next;
         LIST_HEAD(expiredlist);
 
         spin_lock_irqsave(&host->csr.lock, flags);
@@ -746,8 +756,9 @@
 
         spin_lock_irqsave(&host->pending_pkt_lock, flags);
 
-        list_for_each(lh, &host->pending_packets) {
+	for (lh = host->pending_packets.next; lh != &host->pending_packets; lh = next) {
                 packet = list_entry(lh, struct hpsb_packet, list);
+		next = lh->next;
                 if (time_before(packet->sendtime + expire, jiffies)) {
                         list_del(&packet->list);
                         list_add(&packet->list, &expiredlist);
@@ -761,7 +772,7 @@
 
         list_for_each(lh, &expiredlist) {
                 packet = list_entry(lh, struct hpsb_packet, list);
-                packet->state = completed;
+                packet->state = hpsb_complete;
                 packet->ack_code = ACKX_TIMEOUT;
                 up(&packet->state_change);
                 run_task_queue(&packet->complete_tq);
@@ -775,13 +786,19 @@
 					      0, 0, NULL, NULL);
 	init_hpsb_highlevel();
 	init_csr();
-	init_ieee1394_nodemgr();
+	if (!disable_nodemgr)
+		init_ieee1394_nodemgr();
+	else
+		HPSB_INFO("nodemgr functionality disabled");
+
 	return 0;
 }
 
 static void __exit ieee1394_cleanup(void)
 {
-	cleanup_ieee1394_nodemgr();
+	if (!disable_nodemgr)
+		cleanup_ieee1394_nodemgr();
+
 	cleanup_csr();
 	kmem_cache_destroy(hpsb_packet_cache);
 }
diff -urN linux-2.4.11-pre2/drivers/ieee1394/ieee1394_core.h linux/drivers/ieee1394/ieee1394_core.h
--- linux-2.4.11-pre2/drivers/ieee1394/ieee1394_core.h	Fri Sep  7 09:28:38 2001
+++ linux/drivers/ieee1394/ieee1394_core.h	Mon Dec  3 23:15:39 2001
@@ -20,16 +20,16 @@
 
         /* Async and Iso types should be clear, raw means send-as-is, do not
          * CRC!  Byte swapping shall still be done in this case. */
-        enum { async, iso, raw } __attribute__((packed)) type;
+        enum { hpsb_async, hpsb_iso, hpsb_raw } __attribute__((packed)) type;
 
         /* Okay, this is core internal and a no care for hosts.
          * queued   = queued for sending
          * pending  = sent, waiting for response
-         * completed = processing completed, successful or not
+         * complete = processing completed, successful or not
          * incoming = incoming packet
          */
         enum { 
-                unused, queued, pending, completed, incoming 
+                hpsb_unused, hpsb_queued, hpsb_pending, hpsb_complete, hpsb_incoming 
         } __attribute__((packed)) state;
 
         /* These are core internal. */
diff -urN linux-2.4.11-pre2/drivers/ieee1394/ieee1394_hotplug.h linux/drivers/ieee1394/ieee1394_hotplug.h
--- linux-2.4.11-pre2/drivers/ieee1394/ieee1394_hotplug.h	Sun Aug 12 12:39:02 2001
+++ linux/drivers/ieee1394/ieee1394_hotplug.h	Mon Dec  3 23:15:39 2001
@@ -2,32 +2,75 @@
 #define _IEEE1394_HOTPLUG_H
 
 #include "ieee1394_core.h"
+#include "nodemgr.h"
 
-#define IEEE1394_DEVICE_ID_MATCH_VENDOR_ID		0x0001
-#define IEEE1394_DEVICE_ID_MATCH_MODEL_ID		0x0002
-#define IEEE1394_DEVICE_ID_MATCH_SW_SPECIFIER_ID	0x0004
-#define IEEE1394_DEVICE_ID_MATCH_SW_SPECIFIER_VERSION	0x0008
+#define IEEE1394_MATCH_VENDOR_ID	0x0001
+#define IEEE1394_MATCH_MODEL_ID		0x0002
+#define IEEE1394_MATCH_SPECIFIER_ID	0x0004
+#define IEEE1394_MATCH_VERSION		0x0008
 
 struct ieee1394_device_id {
 	u32 match_flags;
 	u32 vendor_id;
 	u32 model_id;
-	u32 sw_specifier_id;
-	u32 sw_specifier_version;
+	u32 specifier_id;
+	u32 version;
+	void *driver_data;
 };
 
-#define IEEE1394_PROTOCOL(id, version) {				       \
-	match_flags:		IEEE1394_DEVICE_ID_MATCH_SW_SPECIFIER_ID |     \
-				IEEE1394_DEVICE_ID_MATCH_SW_SPECIFIER_VERSION, \
-	sw_specifier_id:	id,					       \
-	sw_specifier_version:	version					       \
-}
-
-#define IEEE1394_DEVICE(vendor_id, model_id) {			\
-	match_flags: 	IEEE1394_DEVICE_ID_MATCH_VENDOR_ID |	\
-			IEEE1394_DEVICE_ID_MATCH_MODEL_ID,	\
-	vendor_id:	vendor_id,				\
-	model_id:	vendor_id,				\
-}
+struct hpsb_protocol_driver {
+	/* The name of the driver, e.g. SBP2 or IP1394 */
+	const char *name;
+
+	/* 
+	 * The device id table describing the protocols and/or devices
+	 * supported by this driver.  This is used by the nodemgr to
+	 * decide if a driver could support a given node, but the
+	 * probe function below can implement further protocol
+	 * dependent or vendor dependent checking.
+	 */
+	struct ieee1394_device_id *id_table;
+
+	/* 
+	 * The probe function is called when a device is added to the
+	 * bus and the nodemgr finds a matching entry in the drivers
+	 * device id table or when registering this driver and a
+	 * previously unhandled device can be handled.  The driver may
+	 * decline to handle the device based on further investigation
+	 * of the device (or whatever reason) in which case a negative
+	 * error code should be returned, otherwise 0 should be
+	 * returned. The driver may use the driver_data field in the
+	 * unit directory to store per device driver specific data.
+	 */
+	int (*probe)(struct unit_directory *ud);
+
+	/* 
+	 * The disconnect function is called when a device is removed
+	 * from the bus or if it wasn't possible to read the guid
+	 * after the last bus reset.
+	 */
+	void (*disconnect)(struct unit_directory *ud);
+
+	/* 
+	 * The update function is called when the node has just
+	 * survived a bus reset, i.e. it is still present on the bus.
+	 * However, it may be necessary to reestablish the connection
+	 * or login into the node again, depending on the protocol.
+	 */
+	void (*update)(struct unit_directory *ud);
+
+	/* Driver in list of all registered drivers */
+	struct list_head list;
+
+	/* The list of unit directories managed by this driver */
+	struct list_head unit_directories;
+};
+
+int hpsb_register_protocol(struct hpsb_protocol_driver *driver);
+void hpsb_unregister_protocol(struct hpsb_protocol_driver *driver);
+
+int hpsb_claim_unit_directory(struct unit_directory *ud,
+			      struct hpsb_protocol_driver *driver);
+void hpsb_release_unit_directory(struct unit_directory *ud);
 
 #endif /* _IEEE1394_HOTPLUG_H */
diff -urN linux-2.4.11-pre2/drivers/ieee1394/ieee1394_syms.c linux/drivers/ieee1394/ieee1394_syms.c
--- linux-2.4.11-pre2/drivers/ieee1394/ieee1394_syms.c	Mon Dec  3 23:15:29 2001
+++ linux/drivers/ieee1394/ieee1394_syms.c	Mon Dec  3 23:15:39 2001
@@ -18,6 +18,7 @@
 #include "hosts.h"
 #include "ieee1394_core.h"
 #include "ieee1394_transactions.h"
+#include "ieee1394_hotplug.h"
 #include "highlevel.h"
 #include "nodemgr.h"
 
@@ -75,8 +76,12 @@
 EXPORT_SYMBOL(highlevel_remove_host);
 EXPORT_SYMBOL(highlevel_host_reset);
 EXPORT_SYMBOL(highlevel_add_one_host);
+
 EXPORT_SYMBOL(hpsb_guid_get_entry);
 EXPORT_SYMBOL(hpsb_nodeid_get_entry);
 EXPORT_SYMBOL(hpsb_get_host_by_ne);
 EXPORT_SYMBOL(hpsb_guid_fill_packet);
+EXPORT_SYMBOL(hpsb_register_protocol);
+EXPORT_SYMBOL(hpsb_unregister_protocol);
+EXPORT_SYMBOL(hpsb_release_unit_directory);
 MODULE_LICENSE("GPL");
diff -urN linux-2.4.11-pre2/drivers/ieee1394/ieee1394_transactions.c linux/drivers/ieee1394/ieee1394_transactions.c
--- linux-2.4.11-pre2/drivers/ieee1394/ieee1394_transactions.c	Sun Aug 12 12:39:02 2001
+++ linux/drivers/ieee1394/ieee1394_transactions.c	Mon Dec  3 23:15:39 2001
@@ -131,7 +131,7 @@
 
         packet->header_size = 4;
         packet->data_size = length;
-        packet->type = iso;
+        packet->type = hpsb_iso;
         packet->tcode = TCODE_ISO_DATA;
 }
 
@@ -142,7 +142,7 @@
         packet->header_size = 8;
         packet->data_size = 0;
         packet->expect_response = 0;
-        packet->type = raw;             /* No CRC added */
+        packet->type = hpsb_raw;             /* No CRC added */
         packet->speed_code = SPEED_100; /* Force speed to be 100Mbps */
 }
 
@@ -488,7 +488,9 @@
         if (!packet)
                 return NULL;
 
-        if (length != 4)
+	/* Sometimes this may be called without data, just to allocate the
+	 * packet. */
+        if (length != 4 && buffer)
                 memcpy(packet->data, buffer, length);
 
 	return packet;
diff -urN linux-2.4.11-pre2/drivers/ieee1394/ieee1394_types.h linux/drivers/ieee1394/ieee1394_types.h
--- linux-2.4.11-pre2/drivers/ieee1394/ieee1394_types.h	Sun Aug 12 12:39:02 2001
+++ linux/drivers/ieee1394/ieee1394_types.h	Mon Dec  3 23:15:39 2001
@@ -26,6 +26,13 @@
 #include <linux/spinlock.h>
 #endif
 
+#ifndef list_for_each_safe
+#define list_for_each_safe(pos, n, head) \
+	for (pos = (head)->next, n = pos->next; pos != (head); \
+		pos = n, n = pos->next)
+
+#endif
+
 #ifndef MIN
 #define MIN(a,b) ((a) < (b) ? (a) : (b))
 #endif
diff -urN linux-2.4.11-pre2/drivers/ieee1394/nodemgr.c linux/drivers/ieee1394/nodemgr.c
--- linux-2.4.11-pre2/drivers/ieee1394/nodemgr.c	Mon Sep 17 22:52:35 2001
+++ linux/drivers/ieee1394/nodemgr.c	Mon Dec  3 23:15:39 2001
@@ -15,11 +15,13 @@
 #include <asm/atomic.h>
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
+#include <linux/kmod.h>
 
 #include "ieee1394_types.h"
 #include "ieee1394.h"
 #include "hosts.h"
 #include "ieee1394_transactions.h"
+#include "ieee1394_hotplug.h"
 #include "highlevel.h"
 #include "csr.h"
 #include "nodemgr.h"
@@ -47,6 +49,16 @@
 static LIST_HEAD(node_list);
 static rwlock_t node_lock = RW_LOCK_UNLOCKED;
 
+static LIST_HEAD(driver_list);
+static rwlock_t driver_lock = RW_LOCK_UNLOCKED;
+
+/* The rwlock unit_directory_lock is always held when manipulating the
+ * global unit_directory_list, but this also protects access to the
+ * lists of unit directories stored in the protocol drivers.
+ */
+static LIST_HEAD(unit_directory_list);
+static rwlock_t unit_directory_lock = RW_LOCK_UNLOCKED;
+
 static LIST_HEAD(host_info_list);
 static spinlock_t host_info_lock = SPIN_LOCK_UNLOCKED;
 
@@ -56,7 +68,12 @@
 	struct list_head list;
 };
 
-static struct node_entry *create_node_entry(void)
+static void nodemgr_process_config_rom(struct node_entry *ne, 
+				       quadlet_t busoptions);
+
+
+static struct node_entry *nodemgr_create_node(octlet_t guid, quadlet_t busoptions,
+					      struct hpsb_host *host, nodeid_t nodeid)
 {
         struct node_entry *ne;
         unsigned long flags;
@@ -66,15 +83,21 @@
 
         INIT_LIST_HEAD(&ne->list);
 	INIT_LIST_HEAD(&ne->unit_directories);
-        ne->guid = (u64) -1;
-        ne->host = NULL;
-        ne->nodeid = 0;
-        atomic_set(&ne->generation, -1);
+        ne->host = host;
+        ne->nodeid = nodeid;
+        ne->guid = guid;
+	atomic_set(&ne->generation, get_hpsb_generation(ne->host));
 
         write_lock_irqsave(&node_lock, flags);
         list_add_tail(&ne->list, &node_list);
         write_unlock_irqrestore(&node_lock, flags);
 
+	nodemgr_process_config_rom (ne, busoptions);
+
+	HPSB_DEBUG("%s added: node " NODE_BUS_FMT ", GUID %016Lx",
+		   (host->node_id == nodeid) ? "Local host" : "Device",
+		   NODE_BUS_ARGS(nodeid), (unsigned long long)guid);
+
         return ne;
 }
 
@@ -104,16 +127,20 @@
 	return NULL;
 }
 
-int nodemgr_read_quadlet(struct node_entry *ne, 
+int nodemgr_read_quadlet(struct node_entry *ne,
 			 octlet_t address, quadlet_t *quad)
 {
-	if (hpsb_read(ne->host, ne->nodeid, address, quad, 4)) {
-		HPSB_DEBUG("read of address %Lx failed", address);
-		return -EAGAIN;
+	int i;
+	int ret = 0;
+
+	for (i = 0; i < 3; i++) {
+		ret = hpsb_read(ne->host, ne->nodeid, address, quad, 4);
+		if (ret != -EAGAIN)
+			break;
 	}
 	*quad = be32_to_cpu(*quad);
 
-	return 0;
+	return ret;
 }
 
 #define CONFIG_ROM_VENDOR_ID		0x03
@@ -137,13 +164,14 @@
 	octlet_t a;
 	quadlet_t quad;
 	int length, i;
-	
 
 	if (!(ud = kmalloc (sizeof *ud, GFP_KERNEL)))
 		goto unit_directory_error;
 
 	memset (ud, 0, sizeof *ud);
+	ud->ne = ne;
 	ud->address = address;
+	ud->arb_count = 0;
 
 	if (nodemgr_read_quadlet(ne, address, &quad))
 		goto unit_directory_error;
@@ -151,7 +179,8 @@
 	a = address + 4;
 
 	for (i = 0; i < length; i++, a += 4) {
-		int code, value;
+		int code;
+		quadlet_t value;
 
 		if (nodemgr_read_quadlet(ne, a, &quad))
 			goto unit_directory_error;
@@ -183,10 +212,20 @@
 		case CONFIG_ROM_DESCRIPTOR_DIRECTORY:
 			/* TODO: read strings... icons? */
 			break;
+
+		default:
+			if (ud->arb_count < 16) {
+				/* Place them in the arbitrary pairs */
+				ud->arb_keys[ud->arb_count] = code;
+				ud->arb_values[ud->arb_count] = value;
+				ud->arb_count++;
+			}
 		}
 	}
 
-	list_add_tail (&ud->list, &ne->unit_directories);
+	list_add_tail(&ud->node_list, &ne->unit_directories);
+	list_add_tail(&ud->driver_list, &unit_directory_list);
+
 	return;
 
 unit_directory_error:	
@@ -194,27 +233,29 @@
 		kfree(ud);
 }
 
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
 static void dump_directories (struct node_entry *ne)
 {
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
 	struct list_head *l;
 
 	HPSB_DEBUG("vendor_id=0x%06x, capabilities=0x%06x",
 		   ne->vendor_id, ne->capabilities);
 	list_for_each (l, &ne->unit_directories) {
-		struct unit_directory *ud = list_entry (l, struct unit_directory, list);
+		struct unit_directory *ud = list_entry (l, struct unit_directory, node_list);
 		HPSB_DEBUG("unit directory:");
 		if (ud->flags & UNIT_DIRECTORY_VENDOR_ID)
 			HPSB_DEBUG("  vendor_id=0x%06x ", ud->vendor_id);
 		if (ud->flags & UNIT_DIRECTORY_MODEL_ID)
 			HPSB_DEBUG("  model_id=0x%06x ", ud->model_id);
 		if (ud->flags & UNIT_DIRECTORY_SPECIFIER_ID)
-			HPSB_DEBUG("  specifier_id=0x%06x ", ud->specifier_id);
+			HPSB_DEBUG("  sw_specifier_id=0x%06x ", ud->specifier_id);
 		if (ud->flags & UNIT_DIRECTORY_VERSION)
-			HPSB_DEBUG("  version=0x%06x ", ud->version);
+			HPSB_DEBUG("  sw_version=0x%06x ", ud->version);
 	}
-}
+#else
+	return;
 #endif
+}
 
 static void nodemgr_process_root_directory(struct node_entry *ne)
 {
@@ -260,86 +301,383 @@
 			break;
 		}
 	}
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+
 	dump_directories(ne);
+}
+
+#ifdef CONFIG_HOTPLUG
+
+static void nodemgr_call_policy(char *verb, struct unit_directory *ud)
+{
+	char *argv [3], **envp, *buf, *scratch;
+	int i = 0, value;
+
+	if (!hotplug_path [0])
+		return;
+	if (!current->fs->root)
+		return;
+	if (!(envp = (char **) kmalloc(20 * sizeof (char *), GFP_KERNEL))) {
+		HPSB_DEBUG ("ENOMEM");
+		return;
+	}
+	if (!(buf = kmalloc(256, GFP_KERNEL))) {
+		kfree(envp);
+		HPSB_DEBUG("ENOMEM2");
+		return;
+	}
+
+	/* only one standardized param to hotplug command: type */
+	argv[0] = hotplug_path;
+	argv[1] = "ieee1394";
+	argv[2] = 0;
+
+	/* minimal command environment */
+	envp[i++] = "HOME=/";
+	envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+	/* hint that policy agent should enter no-stdout debug mode */
+	envp[i++] = "DEBUG=kernel";
+#endif
+	/* extensible set of named bus-specific parameters,
+	 * supporting multiple driver selection algorithms.
+	 */
+	scratch = buf;
+
+	envp[i++] = scratch;
+	scratch += sprintf(scratch, "ACTION=%s", verb) + 1;
+	envp[i++] = scratch;
+	scratch += sprintf(scratch, "VENDOR_ID=%06x", ud->ne->vendor_id) + 1;
+	envp[i++] = scratch;
+	scratch += sprintf(scratch, "GUID=%016Lx", (long long unsigned)ud->ne->guid) + 1;
+	envp[i++] = scratch;
+	scratch += sprintf(scratch, "SPECIFIER_ID=%06x", ud->specifier_id) + 1;
+	envp[i++] = scratch;
+	scratch += sprintf(scratch, "VERSION=%06x", ud->version) + 1;
+	envp[i++] = 0;
+
+	/* NOTE: user mode daemons can call the agents too */
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+	HPSB_DEBUG("NodeMgr: %s %s %016Lx", argv[0], verb, (long long unsigned)ud->ne->guid);
 #endif
+	value = call_usermodehelper(argv[0], argv, envp);
+	kfree(buf);
+	kfree(envp);
+	if (value != 0)
+		HPSB_DEBUG("NodeMgr: hotplug policy returned 0x%x", value);
 }
 
-static void register_node(struct hpsb_host *host, nodeid_t nodeid, u64 guid,
-			  quadlet_t busoptions)
+#else
+
+static inline void
+nodemgr_call_policy(char *verb, struct unit_directory *ud)
 {
-        struct node_entry *ne;
-        unsigned long flags, new = 0;
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+	HPSB_DEBUG("NodeMgr: nodemgr_call_policy(): hotplug not enabled");
+#else
+	return;
+#endif
+} 
 
-        read_lock_irqsave(&node_lock, flags);
-        ne = find_entry_by_guid(guid);
-        read_unlock_irqrestore(&node_lock, flags);
+#endif /* CONFIG_HOTPLUG */
 
-	/* New entry */
-	if (!ne) {
-		if ((ne = create_node_entry()) == NULL)
-			return;
+static void nodemgr_claim_unit_directory(struct unit_directory *ud,
+					 struct hpsb_protocol_driver *driver)
+{
+	ud->driver = driver;
+	list_del(&ud->driver_list);
+	list_add_tail(&ud->driver_list, &driver->unit_directories);
+}
+
+static void nodemgr_release_unit_directory(struct unit_directory *ud)
+{
+	ud->driver = NULL;
+	list_del(&ud->driver_list);
+	list_add_tail(&ud->driver_list, &unit_directory_list);
+}
+
+void hpsb_release_unit_directory(struct unit_directory *ud)
+{
+	unsigned long flags;
+
+	write_lock_irqsave(&unit_directory_lock, flags);
+	nodemgr_release_unit_directory(ud);
+	write_unlock_irqrestore(&unit_directory_lock, flags);
+}
+
+static void nodemgr_free_unit_directories(struct node_entry *ne)
+{
+	struct list_head *lh;
+	struct unit_directory *ud;
+
+	lh = ne->unit_directories.next;
+	while (lh != &ne->unit_directories) {
+		ud = list_entry(lh, struct unit_directory, node_list);
+		lh = lh->next;
+		if (ud->driver && ud->driver->disconnect)
+			ud->driver->disconnect(ud);
+		nodemgr_release_unit_directory(ud);
+		nodemgr_call_policy("remove", ud);
+		list_del(&ud->driver_list);
+		kfree(ud);
+	}
+}
+
+static struct ieee1394_device_id *
+nodemgr_match_driver(struct hpsb_protocol_driver *driver, 
+		     struct unit_directory *ud)
+{
+	struct ieee1394_device_id *id;
+
+	for (id = driver->id_table; id->match_flags != 0; id++) {
+		if ((id->match_flags & IEEE1394_MATCH_VENDOR_ID) &&
+		    id->vendor_id != ud->vendor_id)
+			continue;
+
+		if ((id->match_flags & IEEE1394_MATCH_MODEL_ID) &&
+		    id->model_id != ud->model_id)
+			continue;
+
+		if ((id->match_flags & IEEE1394_MATCH_SPECIFIER_ID) &&
+		    id->specifier_id != ud->specifier_id)
+			continue;
+
+		if ((id->match_flags & IEEE1394_MATCH_VERSION) &&
+		    id->version != ud->version)
+			continue;
+
+		return id;
+	}
+
+	return NULL;
+}
+
+static struct hpsb_protocol_driver *
+nodemgr_find_driver(struct unit_directory *ud)
+{
+	struct list_head *l;
+	struct hpsb_protocol_driver *match, *driver;
+	struct ieee1394_device_id *device_id;
+
+	match = NULL;
+	list_for_each(l, &driver_list) {
+		driver = list_entry(l, struct hpsb_protocol_driver, list);
+		device_id = nodemgr_match_driver(driver, ud);
+
+		if (device_id != NULL) {
+			match = driver;
+			break;
+		}
+	}
+
+	return match;
+}
+
+static void nodemgr_bind_drivers (struct node_entry *ne)
+{
+	struct list_head *lh;
+	struct hpsb_protocol_driver *driver;
+	struct unit_directory *ud;
 
-		HPSB_DEBUG("%s added: node " NODE_BUS_FMT
-			   ", GUID %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
-			   (host->node_id == nodeid) ? "Local host" : "Device",
-			   NODE_BUS_ARGS(nodeid), ((u8 *)&guid)[0],
-			   ((u8 *)&guid)[1], ((u8 *)&guid)[2], ((u8 *)&guid)[3],
-			   ((u8 *)&guid)[4], ((u8 *)&guid)[5], ((u8 *)&guid)[6],
-			   ((u8 *)&guid)[7]);
+	list_for_each(lh, &ne->unit_directories) {
+		ud = list_entry(lh, struct unit_directory, node_list);
+		driver = nodemgr_find_driver(ud);
+		if (driver != NULL && driver->probe(ud) == 0)
+			nodemgr_claim_unit_directory(ud, driver);
+		nodemgr_call_policy("add", ud);
+	}
+}
+
+int hpsb_register_protocol(struct hpsb_protocol_driver *driver)
+{
+	struct unit_directory *ud;
+	struct list_head *lh;
+	unsigned long flags;
+
+        write_lock_irqsave(&driver_lock, flags);
+	list_add_tail(&driver->list, &driver_list);
+	write_unlock_irqrestore(&driver_lock, flags);
+
+	write_lock_irqsave(&unit_directory_lock, flags);
+	INIT_LIST_HEAD(&driver->unit_directories);
+	lh = unit_directory_list.next;
+	while (lh != &unit_directory_list) {
+		ud = list_entry(lh, struct unit_directory, driver_list);
+		lh = lh->next;
+		if (nodemgr_match_driver(driver, ud) && driver->probe(ud) == 0)
+			nodemgr_claim_unit_directory(ud, driver);
+	}
+	write_unlock_irqrestore(&unit_directory_lock, flags);
+
+	/*
+	 * Right now registration always succeeds, but maybe we should
+	 * detect clashes in protocols handled by other drivers.
+	 */
+
+	return 0;
+}
+
+void hpsb_unregister_protocol(struct hpsb_protocol_driver *driver)
+{
+	struct list_head *lh;
+	struct unit_directory *ud;
+	unsigned long flags;
 
-		ne->guid = guid;
-		new = 1;
+        write_lock_irqsave(&driver_lock, flags);
+	list_del(&driver->list);
+	write_unlock_irqrestore(&driver_lock, flags);
+
+	write_lock_irqsave(&unit_directory_lock, flags);
+	lh = driver->unit_directories.next;
+	while (lh != &driver->unit_directories) {
+		ud = list_entry(lh, struct unit_directory, driver_list);
+		lh = lh->next;
+		if (ud->driver && ud->driver->disconnect)
+			ud->driver->disconnect(ud);
+		nodemgr_release_unit_directory(ud);
 	}
+	write_unlock_irqrestore(&unit_directory_lock, flags);
+}
+
+static void nodemgr_process_config_rom(struct node_entry *ne, 
+				       quadlet_t busoptions)
+{
+	unsigned long flags;
+
+	ne->busopt.irmc		= (busoptions >> 31) & 1;
+	ne->busopt.cmc		= (busoptions >> 30) & 1;
+	ne->busopt.isc		= (busoptions >> 29) & 1;
+	ne->busopt.bmc		= (busoptions >> 28) & 1;
+	ne->busopt.pmc		= (busoptions >> 27) & 1;
+	ne->busopt.cyc_clk_acc	= (busoptions >> 16) & 0xff;
+	ne->busopt.max_rec	= 1 << (((busoptions >> 12) & 0xf) + 1);
+	ne->busopt.generation	= (busoptions >> 4) & 0xf;
+	ne->busopt.lnkspd	= busoptions & 0x7;
 
-	if (!new && ne->nodeid != nodeid)
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+	HPSB_DEBUG("NodeMgr: raw=0x%08x irmc=%d cmc=%d isc=%d bmc=%d pmc=%d "
+		   "cyc_clk_acc=%d max_rec=%d gen=%d lspd=%d",
+		   busoptions, ne->busopt.irmc, ne->busopt.cmc,
+		   ne->busopt.isc, ne->busopt.bmc, ne->busopt.pmc,
+		   ne->busopt.cyc_clk_acc, ne->busopt.max_rec,
+		   ne->busopt.generation, ne->busopt.lnkspd);
+#endif
+
+	/*
+	 * When the config rom changes we disconnect all drivers and
+	 * free the cached unit directories and reread the whole
+	 * thing.  If this was a new device, the call to
+	 * nodemgr_disconnect_drivers is a no-op and all is well.
+	 */
+	write_lock_irqsave(&unit_directory_lock, flags);
+	nodemgr_free_unit_directories(ne);
+	nodemgr_process_root_directory(ne);
+	nodemgr_bind_drivers(ne);
+	write_unlock_irqrestore(&unit_directory_lock, flags);
+}
+
+/*
+ * This function updates nodes that were present on the bus before the
+ * reset and still are after the reset.  The nodeid and the config rom
+ * may have changed, and the drivers managing this device must be
+ * informed that this device just went through a bus reset, to allow
+ * the to take whatever actions required.
+ */
+static void nodemgr_update_node(struct node_entry *ne, quadlet_t busoptions,
+                               struct hpsb_host *host, nodeid_t nodeid)
+{
+	struct list_head *lh;
+
+	if (ne->nodeid != nodeid)
 		HPSB_DEBUG("Node " NODE_BUS_FMT " changed to " NODE_BUS_FMT,
 			   NODE_BUS_ARGS(ne->nodeid), NODE_BUS_ARGS(nodeid));
 
 	ne->host = host;
-        ne->nodeid = nodeid;
+	ne->nodeid = nodeid;
 
-	/* Now set the bus options. Only do all this crap if this is a new
-	 * node, or if the generation number has changed.  */
-	if (new || ne->busopt.generation != ((busoptions >> 6) & 0x3)) {
-		ne->busopt.irmc		= (busoptions >> 31) & 1;
-		ne->busopt.cmc		= (busoptions >> 30) & 1;
-		ne->busopt.isc		= (busoptions >> 29) & 1;
-		ne->busopt.bmc		= (busoptions >> 28) & 1;
-		ne->busopt.pmc		= (busoptions >> 27) & 1;
-		ne->busopt.cyc_clk_acc	= (busoptions >> 16) & 0xff;
-		ne->busopt.max_rec	= 1 << (((busoptions >> 12) & 0xf) + 1);
-		ne->busopt.generation	= (busoptions >> 6) & 0x3;
-		ne->busopt.lnkspd	= busoptions & 0x7;
+	if (ne->busopt.generation != ((busoptions >> 4) & 0xf))
+		nodemgr_process_config_rom (ne, busoptions);
 
-		/* Now, process the rest of the tree */
-		nodemgr_process_root_directory(ne);
+	/* Since that's done, we can declare this record current */
+	atomic_set(&ne->generation, get_hpsb_generation(ne->host));
+
+	list_for_each (lh, &ne->unit_directories) {
+		struct unit_directory *ud;
+
+		ud = list_entry (lh, struct unit_directory, node_list);
+		if (ud->driver != NULL && ud->driver->update != NULL)
+			ud->driver->update(ud);
 	}
+}
 
-	/* Since that's done, we can declare this record current */
-	atomic_set(&ne->generation, get_hpsb_generation(host));
+static int read_businfo_block(struct hpsb_host *host, nodeid_t nodeid,
+			      quadlet_t *buffer, int buffer_length)
+{
+	octlet_t base = CSR_REGISTER_BASE + CSR_CONFIG_ROM;
+	int retries = 3;
+	int header_count;
+	unsigned header_size;
+	quadlet_t quad;
+
+retry_configrom:
+
+	if (!retries--) {
+		HPSB_ERR("Giving up on node " NODE_BUS_FMT
+			 " for ConfigROM probe, too many errors",
+			 NODE_BUS_ARGS(nodeid));
+		return -1;
+	}
+
+	header_count = 0;
+	header_size = 0;
 
 #ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-	HPSB_DEBUG("raw=0x%08x irmc=%d cmc=%d isc=%d bmc=%d pmc=%d cyc_clk_acc=%d "
-		   "max_rec=%d gen=%d lspd=%d", busoptions,
-		   ne->busopt.irmc, ne->busopt.cmc, ne->busopt.isc, ne->busopt.bmc,
-		   ne->busopt.pmc, ne->busopt.cyc_clk_acc, ne->busopt.max_rec,
-		   ne->busopt.generation, ne->busopt.lnkspd);
+	HPSB_INFO("Initiating ConfigROM request for node " NODE_BUS_FMT,
+		  NODE_BUS_ARGS(nodeid));
 #endif
 
-	return;
+	/* Now, P1212 says that devices should support 64byte block
+	 * reads, aligned on 64byte boundaries. That doesn't seem
+	 * to work though, and we are forced to doing quadlet
+	 * sized reads.  */
+
+	if (hpsb_read(host, nodeid, base, &quad, 4)) {
+		HPSB_ERR("ConfigROM quadlet transaction error for node " NODE_BUS_FMT,
+			 NODE_BUS_ARGS(nodeid));
+		goto retry_configrom;
+	}
+	buffer[header_count++] = be32_to_cpu(quad);
+
+	header_size = buffer[0] >> 24;
+
+	if (header_size < 4) {
+		HPSB_INFO("Node " NODE_BUS_FMT " has non-standard ROM format (%d quads), "
+			  "cannot parse", NODE_BUS_ARGS(nodeid), header_size);
+		return -1;
+	}
+
+	while (header_count <= header_size && header_count < buffer_length) {
+		if (hpsb_read(host, nodeid, base + (header_count<<2), &quad, 4)) {
+			HPSB_ERR("ConfigROM quadlet transaction error for " NODE_BUS_FMT,
+				 NODE_BUS_ARGS(nodeid));
+			goto retry_configrom;
+		}
+		buffer[header_count++] = be32_to_cpu(quad);
+	}
+
+	return 0;
 }
 
 static void nodemgr_remove_node(struct node_entry *ne)
 {
-	HPSB_DEBUG("Device removed: node " NODE_BUS_FMT ", GUID "
-		   "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
-		   NODE_BUS_ARGS(ne->nodeid),
-		   ((u8 *)&ne->guid)[0], ((u8 *)&ne->guid)[1],
-		   ((u8 *)&ne->guid)[2], ((u8 *)&ne->guid)[3],
-		   ((u8 *)&ne->guid)[4], ((u8 *)&ne->guid)[5],
-		   ((u8 *)&ne->guid)[6], ((u8 *)&ne->guid)[7]);
+	unsigned long flags;
 
+	HPSB_DEBUG("Device removed: node " NODE_BUS_FMT ", GUID %016Lx",
+		   NODE_BUS_ARGS(ne->nodeid), (unsigned long long)ne->guid);
+
+	write_lock_irqsave(&unit_directory_lock, flags);
+	nodemgr_free_unit_directories(ne);
+	write_unlock_irqrestore(&unit_directory_lock, flags);
 	list_del(&ne->list);
 	kfree(ne);
 
@@ -352,82 +690,26 @@
 {
 	struct hpsb_host *host = (struct hpsb_host *)data;
         struct selfid *sid = (struct selfid *)host->topology_map;
-	struct list_head *lh,*spare;
+	struct list_head *lh, *next;
 	struct node_entry *ne;
         int nodecount = host->node_count;
         nodeid_t nodeid = LOCAL_BUS;
-	quadlet_t buffer[5], quad;
-	octlet_t base = CSR_REGISTER_BASE + CSR_CONFIG_ROM;
+	quadlet_t buffer[5];
+	octlet_t guid;
 	unsigned long flags;
 
 	/* We need to detect when the ConfigROM's generation has changed,
 	 * so we only update the node's info when it needs to be.  */
         for (; nodecount; nodecount--, nodeid++, sid++) {
-		int retries = 3;
-		int header_count;
-		unsigned header_size;
-		octlet_t guid;
-
 		/* Skip extended, and non-active node's */
                 while (sid->extended)
 			sid++;
                 if (!sid->link_active)
 			continue;
 
-		/* Just use our local ROM */
-		if (nodeid == host->node_id) {
-			int i;
-			for (i = 0; i < 5; i++)
-				buffer[i] = be32_to_cpu(host->csr.rom[i]);
-			goto set_options;
-		}
-
-retry_configrom:
-		
-		if (!retries--) {
-			HPSB_ERR("Giving up on node " NODE_BUS_FMT
-				 " for ConfigROM probe, too many errors",
-				 NODE_BUS_ARGS(nodeid));
+		if (read_businfo_block (host, nodeid, buffer, sizeof(buffer) >> 2))
 			continue;
-		}
-
-		header_count = 0;
-		header_size = 0;
-
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-		HPSB_INFO("Initiating ConfigROM request for node " NODE_BUS_FMT,
-			  NODE_BUS_ARGS(nodeid));
-#endif
 
-		/* Now, P1212 says that devices should support 64byte block
-		 * reads, aligned on 64byte boundaries. That doesn't seem
-		 * to work though, and we are forced to doing quadlet
-		 * sized reads.  */
-
-		if (hpsb_read(host, nodeid, base, &quad, 4)) {
-			HPSB_ERR("ConfigROM quadlet transaction error for node " NODE_BUS_FMT,
-				 NODE_BUS_ARGS(nodeid));
-			goto retry_configrom;
-		}
-		buffer[header_count++] = be32_to_cpu(quad);
-
-		header_size = buffer[0] >> 24;
-
-		if (header_size < 4) {
-			HPSB_INFO("Node " NODE_BUS_FMT " has non-standard ROM format (%d quads), "
-				  "cannot parse", NODE_BUS_ARGS(nodeid), header_size);
-			continue;
-		}
-
-		while (header_count <= header_size && (header_count<<2) < sizeof(buffer)) {
-			if (hpsb_read(host, nodeid, base + (header_count<<2), &quad, 4)) {
-				HPSB_ERR("ConfigROM quadlet transaction error for " NODE_BUS_FMT,
-					 NODE_BUS_ARGS(nodeid));
-				goto retry_configrom;
-			}
-			buffer[header_count++] = be32_to_cpu(quad);
-		}
-set_options:
 		if (buffer[1] != IEEE1394_BUSID_MAGIC) {
 			/* This isn't a 1394 device */
 			HPSB_ERR("Node " NODE_BUS_FMT " isn't an IEEE 1394 device",
@@ -435,15 +717,21 @@
 			continue;
 		}
 
-		guid = be64_to_cpu(((u64)buffer[3] << 32) | buffer[4]);
-		register_node(host, nodeid, guid, buffer[2]);
+		guid = ((u64)buffer[3] << 32) | buffer[4];
+		ne = hpsb_guid_get_entry(guid);
+
+		if (!ne)
+			nodemgr_create_node(guid, buffer[2], host, nodeid);
+		else
+			nodemgr_update_node(ne, buffer[2], host, nodeid);
         }
 
 	/* Now check to see if we have any nodes that aren't referenced
 	 * any longer.  */
         write_lock_irqsave(&node_lock, flags);
-	list_for_each_safe(lh, spare, &node_list) {
+	for (lh = node_list.next; lh != &node_list; lh = next) {
 		ne = list_entry(lh, struct node_entry, list);
+		next = lh->next;
 
 		/* Only checking this host */
 		if (ne->host != host)
@@ -453,7 +741,7 @@
 		 * node was removed, or it failed the above probe. Either
 		 * way, we remove references to it, since they are
 		 * invalid.  */
-		if (atomic_read(&ne->generation) != get_hpsb_generation(host))
+		if (!hpsb_node_entry_valid(ne))
 			nodemgr_remove_node(ne);
 	}
 	write_unlock_irqrestore(&node_lock, flags);
@@ -511,7 +799,7 @@
 	unsigned long flags;
 
 	if (!hi) {
-		HPSB_ERR ("Out of memory in Node Manager");
+		HPSB_ERR ("NodeMgr: out of memory in add host");
 		return;
 	}
 
@@ -544,7 +832,7 @@
 	}
 
 	if (hi == NULL) {
-		HPSB_ERR ("Could not process reset of non-existent host in Node Manager");
+		HPSB_ERR ("NodeMgr: could not process reset of non-existent host");
 		goto done_reset_host;
 	}
 
@@ -558,8 +846,7 @@
 
 static void nodemgr_remove_host(struct hpsb_host *host)
 {
-	struct list_head *lh;
-	struct host_info *hi = NULL;
+	struct list_head *lh, *next;
 	struct node_entry *ne;
 	unsigned long flags;
 
@@ -568,8 +855,10 @@
 
 	/* First remove all node entries for this host */
 	write_lock_irqsave(&node_lock, flags);
-	list_for_each(lh, &node_list) {
+
+	for (lh = node_list.next; lh != &node_list; lh = next) {
 		ne = list_entry(lh, struct node_entry, list);
+		next = lh->next;
 
 		/* Only checking this host */
 		if (ne->host != host)
@@ -581,22 +870,17 @@
 
 	spin_lock_irqsave (&host_info_lock, flags);
 	list_for_each(lh, &host_info_list) {
-		struct host_info *myhi = list_entry(lh, struct host_info, list);
-		if (myhi->host == host) {
-			hi = myhi;
+		struct host_info *hi = list_entry(lh, struct host_info, list);
+		if (hi->host == host) {
+			list_del(&hi->list);
+			kfree (hi);
 			break;
 		}
 	}
 
-	if (hi == NULL) {
-		HPSB_ERR ("Could not remove non-existent host in Node Manager");
-		goto done_remove_host;
-	}
-
-	list_del(&hi->list);
-	kfree (hi);
+	if (lh == host_info_list.next)
+		HPSB_ERR ("NodeMgr: could not remove non-existent host");
 
-done_remove_host:
 	spin_unlock_irqrestore (&host_info_lock, flags);
 
 	return;
@@ -614,7 +898,7 @@
 {
         hl = hpsb_register_highlevel("Node manager", &nodemgr_ops);
         if (!hl) {
-                HPSB_ERR("Out of memory during ieee1394 initialization");
+		HPSB_ERR("NodeMgr: out of memory during ieee1394 initialization");
         }
 }
 
diff -urN linux-2.4.11-pre2/drivers/ieee1394/nodemgr.h linux/drivers/ieee1394/nodemgr.h
--- linux-2.4.11-pre2/drivers/ieee1394/nodemgr.h	Sun Aug 12 12:39:02 2001
+++ linux/drivers/ieee1394/nodemgr.h	Mon Dec  3 23:15:39 2001
@@ -38,13 +38,23 @@
 	u16	max_rec;	/* Maximum packet size node can receive */
 };
 
-#define UNIT_DIRECTORY_VENDOR_ID    0x01
-#define UNIT_DIRECTORY_MODEL_ID     0x02
-#define UNIT_DIRECTORY_SPECIFIER_ID 0x04
-#define UNIT_DIRECTORY_VERSION      0x08
+#define UNIT_DIRECTORY_VENDOR_ID	0x01
+#define UNIT_DIRECTORY_MODEL_ID		0x02
+#define UNIT_DIRECTORY_SPECIFIER_ID	0x04
+#define UNIT_DIRECTORY_VERSION		0x08
 
+/*
+ * A unit directory corresponds to a protocol supported by the
+ * node. If a node supports eg. IP/1394 and AV/C, its config rom has a
+ * unit directory for each of these protocols.
+ * 
+ * Unit directories appear on two types of lists: for each node we
+ * maintain a list of the unit directories found in its config rom and
+ * for each driver we maintain a list of the unit directories
+ * (ie. devices) the driver manages.
+ */
 struct unit_directory {
-	struct list_head list;
+	struct node_entry *ne;  /* The node which this directory belongs to */
 	octlet_t address;	/* Address of the unit directory on the node */
 	u8 flags;		/* Indicates which entries were read */
 	quadlet_t vendor_id;
@@ -53,6 +63,20 @@
 	char *model_name;
 	quadlet_t specifier_id;
 	quadlet_t version;
+
+	/* Groupings for arbitrary key/value pairs */
+	int arb_count;			/* Number of arbitrary key/values */
+	char arb_keys[16];		/* Up to 16 keys */
+	quadlet_t arb_values[16];	/* Same for values */
+
+	struct hpsb_protocol_driver *driver;
+	void *driver_data;
+
+	/* For linking the nodes managed by the driver, or unmanaged nodes */
+	struct list_head driver_list;
+
+	/* For linking directories belonging to a node */
+	struct list_head node_list;
 };
 
 struct node_entry {
@@ -68,6 +92,11 @@
 	u32 capabilities;	
 	struct list_head unit_directories;
 };
+
+static inline int hpsb_node_entry_valid(struct node_entry *ne)
+{
+	return atomic_read(&ne->generation) == get_hpsb_generation(ne->host);
+}
 
 /*
  * Returns a node entry (which has its reference count incremented) or NULL if
diff -urN linux-2.4.11-pre2/drivers/ieee1394/ohci1394.c linux/drivers/ieee1394/ohci1394.c
--- linux-2.4.11-pre2/drivers/ieee1394/ohci1394.c	Mon Dec  3 23:15:29 2001
+++ linux/drivers/ieee1394/ohci1394.c	Mon Dec  3 23:15:39 2001
@@ -105,6 +105,17 @@
 #include <linux/vmalloc.h>
 #include <linux/init.h>
 
+#ifdef CONFIG_ALL_PPC
+#include <asm/feature.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#endif
+
+/* Revert to old bus reset algorithm that works on my Pismo until
+ * the new one is fixed
+ */
+#undef BUSRESET_WORKAROUND
+
 #include "ieee1394.h"
 #include "ieee1394_types.h"
 #include "hosts.h"
@@ -112,7 +123,6 @@
 #include "highlevel.h"
 #include "ohci1394.h"
 
-
 #ifdef CONFIG_IEEE1394_VERBOSEDEBUG
 #define OHCI1394_DEBUG
 #endif
@@ -123,17 +133,17 @@
 
 #ifdef OHCI1394_DEBUG
 #define DBGMSG(card, fmt, args...) \
-printk(KERN_INFO "ohci1394_%d: " fmt "\n" , card , ## args)
+printk(KERN_INFO "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args)
 #else
 #define DBGMSG(card, fmt, args...)
 #endif
 
 #ifdef CONFIG_IEEE1394_OHCI_DMA_DEBUG
 #define OHCI_DMA_ALLOC(fmt, args...) \
-	HPSB_ERR("ohci1394("__FUNCTION__")alloc(%d): "fmt, \
+	HPSB_ERR("%s("__FUNCTION__")alloc(%d): "fmt, OHCI1394_DRIVER_NAME, \
 		++global_outstanding_dmas, ## args)
 #define OHCI_DMA_FREE(fmt, args...) \
-	HPSB_ERR("ohci1394("__FUNCTION__")free(%d): "fmt, \
+	HPSB_ERR("%s("__FUNCTION__")free(%d): "fmt, OHCI1394_DRIVER_NAME, \
 		--global_outstanding_dmas, ## args)
 u32 global_outstanding_dmas = 0;
 #else
@@ -143,18 +153,11 @@
 
 /* print general (card independent) information */
 #define PRINT_G(level, fmt, args...) \
-printk(level "ohci1394: " fmt "\n" , ## args)
+printk(level "%s: " fmt "\n" , OHCI1394_DRIVER_NAME , ## args)
 
 /* print card specific information */
 #define PRINT(level, card, fmt, args...) \
-printk(level "ohci1394_%d: " fmt "\n" , card , ## args)
-
-#define FAIL(fmt, args...)				\
-do {							\
-	PRINT_G(KERN_ERR, fmt , ## args);		\
-	remove_card(ohci);				\
-	return 1;					\
-} while(0)
+printk(level "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args)
 
 #define PCI_CLASS_FIREWIRE_OHCI     ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10)
 
@@ -179,21 +182,48 @@
 MODULE_PARM_DESC(attempt_root, "Attempt to make the host root.");
 static int attempt_root = 0;
 
-#ifdef __LITTLE_ENDIAN
-/* Don't waste cycles on same sex byte swaps */
-#define packet_swab(w,x,y,z)
-#define block_swab32(x,y)
-#else
-static void packet_swab(quadlet_t *data, char tcode, int len, int payload_swap);
-static __inline__ void block_swab32(quadlet_t *data, size_t size);
-#endif
-
 static unsigned int card_id_counter = 0;
 
 static void dma_trm_tasklet(unsigned long data);
 static void remove_card(struct ti_ohci *ohci);
 static void dma_trm_reset(struct dma_trm_ctx *d);
 
+#ifndef __LITTLE_ENDIAN
+/* Swap a series of quads inplace. */
+static __inline__ void block_swab32(quadlet_t *data, size_t size) {
+	while (size--)
+		data[size] = swab32(data[size]);
+}
+
+static unsigned hdr_sizes[] = 
+{
+	3,	/* TCODE_WRITEQ */
+	4,	/* TCODE_WRITEB */
+	3,	/* TCODE_WRITE_RESPONSE */
+	0,	/* ??? */
+	3,	/* TCODE_READQ */
+	4,	/* TCODE_READB */
+	3,	/* TCODE_READQ_RESPONSE */
+	4,	/* TCODE_READB_RESPONSE */
+	1,	/* TCODE_CYCLE_START (???) */
+	4,	/* TCODE_LOCK_REQUEST */
+	2,	/* TCODE_ISO_DATA */
+	4,	/* TCODE_LOCK_RESPONSE */
+};
+
+/* Swap headers */
+static inline void packet_swab(quadlet_t *data, int tcode, int len)
+{
+	if (tcode > TCODE_LOCK_RESPONSE || hdr_sizes[tcode] == 0)
+		return;
+	block_swab32(data, hdr_sizes[tcode]);
+}
+#else
+/* Don't waste cycles on same sex byte swaps */
+#define packet_swab(w,x,y)
+#define block_swab32(x,y)
+#endif /* !LITTLE_ENDIAN */
+
 /***********************************
  * IEEE-1394 functionality section *
  ***********************************/
@@ -230,7 +260,7 @@
 {
 	int i;
 	unsigned long flags;
-	u32 r;
+	u32 r = 0;
 
 	spin_lock_irqsave (&ohci->phy_reg_lock, flags);
 
@@ -376,7 +406,7 @@
 }
 
 /* Generate the dma receive prgs and start the context */
-static void initialize_dma_rcv_ctx(struct dma_rcv_ctx *d)
+static void initialize_dma_rcv_ctx(struct dma_rcv_ctx *d, int generate_irq)
 {
 	struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
 	int i;
@@ -384,12 +414,17 @@
 	ohci1394_stop_context(ohci, d->ctrlClear, NULL);
 
 	for (i=0; i<d->num_desc; i++) {
+		u32 c;
 		
-		d->prg_cpu[i]->control =
-                   cpu_to_le32((0x280C << 16) | d->buf_size);
+		c = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
+			DMA_CTL_BRANCH;
+		if (generate_irq)
+			c |= DMA_CTL_IRQ;
+				
+		d->prg_cpu[i]->control = cpu_to_le32(c | d->buf_size);
 
 		/* End of descriptor list? */
-		if ((i+1) < d->num_desc) {
+		if (i + 1 < d->num_desc) {
 			d->prg_cpu[i]->branchAddress =
 				cpu_to_le32((d->prg_bus[i+1] & 0xfffffff0) | 0x1);
 		} else {
@@ -565,15 +600,15 @@
 	reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 0xffffffff);
 
 	/* Initialize AR dma */
-	initialize_dma_rcv_ctx(ohci->ar_req_context);
-	initialize_dma_rcv_ctx(ohci->ar_resp_context);
+	initialize_dma_rcv_ctx(ohci->ar_req_context, 0);
+	initialize_dma_rcv_ctx(ohci->ar_resp_context, 0);
 
 	/* Initialize AT dma */
 	initialize_dma_trm_ctx(ohci->at_req_context);
 	initialize_dma_trm_ctx(ohci->at_resp_context);
 
 	/* Initialize IR dma */
-	initialize_dma_rcv_ctx(ohci->ir_context);
+	initialize_dma_rcv_ctx(ohci->ir_context, 1);
 
         /* Initialize IT dma */
         initialize_dma_trm_ctx(ohci->it_context);
@@ -604,7 +639,6 @@
 	/* Enable interrupts */
 	reg_write(ohci, OHCI1394_IntMaskSet, 
 		  OHCI1394_masterIntEnable | 
-		  OHCI1394_phyRegRcvd | 
 		  OHCI1394_busReset | 
 		  OHCI1394_selfIDComplete |
 		  OHCI1394_RSPkt |
@@ -674,9 +708,9 @@
 	} else 
 		d->prg_cpu[idx]->begin.status = 0;
 
-        if ( (packet->type == async) || (packet->type == raw) ) {
+        if ( (packet->type == hpsb_async) || (packet->type == hpsb_raw) ) {
 
-                if (packet->type == raw) {
+                if (packet->type == hpsb_raw) {
 			d->prg_cpu[idx]->data[0] = cpu_to_le32(OHCI1394_TCODE_PHY<<4);
                         d->prg_cpu[idx]->data[1] = packet->header[0];
                         d->prg_cpu[idx]->data[2] = packet->header[1];
@@ -689,14 +723,18 @@
                         d->prg_cpu[idx]->data[2] = packet->header[2];
                         d->prg_cpu[idx]->data[3] = packet->header[3];
 			packet_swab(d->prg_cpu[idx]->data, packet->tcode,
-					packet->header_size>>2, ohci->payload_swap);
+					packet->header_size>>2);
                 }
 
                 if (packet->data_size) { /* block transmit */
                         d->prg_cpu[idx]->begin.control =
-                                cpu_to_le32(OUTPUT_MORE_IMMEDIATE | 0x10);
+                                cpu_to_le32(DMA_CTL_OUTPUT_MORE |
+					    DMA_CTL_IMMEDIATE | 0x10);
                         d->prg_cpu[idx]->end.control =
-                                cpu_to_le32(OUTPUT_LAST | packet->data_size);
+                                cpu_to_le32(DMA_CTL_OUTPUT_LAST |
+					    DMA_CTL_IRQ | 
+					    DMA_CTL_BRANCH |
+					    packet->data_size);
                         /* 
                          * Check that the packet data buffer
                          * does not cross a page boundary.
@@ -716,9 +754,6 @@
                                                PCI_DMA_TODEVICE));
 			OHCI_DMA_ALLOC("single, block transmit packet");
 
-			if (ohci->payload_swap)
-				block_swab32(packet->data, packet->data_size >> 2);
-
                         d->prg_cpu[idx]->end.branchAddress = 0;
                         d->prg_cpu[idx]->end.status = 0;
                         if (d->branchAddrPtr) 
@@ -727,14 +762,20 @@
                         d->branchAddrPtr =
                                 &(d->prg_cpu[idx]->end.branchAddress);
                 } else { /* quadlet transmit */
-                        if (packet->type == raw)
-                                d->prg_cpu[idx]->begin.control = cpu_to_le32(
-                                        OUTPUT_LAST_IMMEDIATE |
-                                        (packet->header_size+4));
+                        if (packet->type == hpsb_raw)
+                                d->prg_cpu[idx]->begin.control = 
+					cpu_to_le32(DMA_CTL_OUTPUT_LAST |
+						    DMA_CTL_IMMEDIATE |
+						    DMA_CTL_IRQ | 
+						    DMA_CTL_BRANCH |
+						    (packet->header_size + 4));
                         else
-                                d->prg_cpu[idx]->begin.control = cpu_to_le32(
-                                        OUTPUT_LAST_IMMEDIATE |
-                                        packet->header_size);
+                                d->prg_cpu[idx]->begin.control =
+					cpu_to_le32(DMA_CTL_OUTPUT_LAST |
+						    DMA_CTL_IMMEDIATE |
+						    DMA_CTL_IRQ | 
+						    DMA_CTL_BRANCH |
+						    packet->header_size);
 
                         if (d->branchAddrPtr) 
                                 *(d->branchAddrPtr) =
@@ -747,20 +788,22 @@
                 d->prg_cpu[idx]->data[0] = packet->speed_code<<16 |
                         (packet->header[0] & 0xFFFF);
                 d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000;
-		packet_swab(d->prg_cpu[idx]->data, packet->tcode, packet->header_size>>2,
-				ohci->payload_swap);
+		packet_swab(d->prg_cpu[idx]->data, packet->tcode, packet->header_size>>2);
   
-                d->prg_cpu[idx]->begin.control = cpu_to_le32(OUTPUT_MORE_IMMEDIATE | 0x8);
-                d->prg_cpu[idx]->end.control = cpu_to_le32(
-                        OUTPUT_LAST | 0x08000000 | packet->data_size);
+                d->prg_cpu[idx]->begin.control = 
+			cpu_to_le32(DMA_CTL_OUTPUT_MORE | 
+				    DMA_CTL_IMMEDIATE | 0x8);
+                d->prg_cpu[idx]->end.control = 
+			cpu_to_le32(DMA_CTL_OUTPUT_LAST |
+				    DMA_CTL_UPDATE |
+				    DMA_CTL_IRQ |
+				    DMA_CTL_BRANCH |
+				    packet->data_size);
                 d->prg_cpu[idx]->end.address = cpu_to_le32(
 				pci_map_single(ohci->dev, packet->data,
 				packet->data_size, PCI_DMA_TODEVICE));
 		OHCI_DMA_ALLOC("single, iso transmit packet");
 
-		if (ohci->payload_swap)
-			block_swab32(packet->data, packet->data_size>>2);
-
                 d->prg_cpu[idx]->end.branchAddress = 0;
                 d->prg_cpu[idx]->end.status = 0;
                 DBGMSG(ohci->id, "Iso xmit context info: header[%08x %08x]\n"
@@ -947,7 +990,7 @@
 
 		if (arg<0 || arg>63) {
 			PRINT(KERN_ERR, ohci->id, __FUNCTION__
-			      "IS0 listne channel %d is out of range", 
+			      "IS0 listen channel %d is out of range", 
 			      arg);
 			return -EFAULT;
 		}
@@ -1083,13 +1126,16 @@
 	int phyid = -1, isroot = 0;
 	unsigned long flags;
 
-	/* Read the interrupt event register. We don't clear the bus reset
-	 * here. We wait till we get a selfid complete interrupt and clear
-	 * it then, and _only_ then.  */
+	/* Read and clear the interrupt event register.  Don't clear
+	 * the busReset event, though, this is done when we get the
+	 * selfIDComplete interrupt. */
 	spin_lock_irqsave(&ohci->event_lock, flags);
 	event = reg_read(ohci, OHCI1394_IntEventClear);
-	reg_write(ohci, OHCI1394_IntEventClear,
-		  event & ~(OHCI1394_selfIDComplete | OHCI1394_busReset));
+#ifdef BUSRESET_WORKAROUND
+	reg_write(ohci, OHCI1394_IntEventClear, event);
+#else
+	reg_write(ohci, OHCI1394_IntEventClear, event & ~OHCI1394_busReset);
+#endif
 	spin_unlock_irqrestore(&ohci->event_lock, flags);
 
 	if (!event) return;
@@ -1103,24 +1149,26 @@
 		return;
 	}
 
-	/* Someone wants a bus reset. Better watch what you wish for... */
 	if (event & OHCI1394_busReset) {
+		/* The busReset event bit can't be cleared during the
+		 * selfID phase, so we disable busReset interrupts, to
+		 * avoid burying the cpu in interrupt requests. */
+		spin_lock_irqsave(&ohci->event_lock, flags);
+#ifdef BUSRESET_WORKAROUND
+		reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
+#else
+  		reg_write(ohci, OHCI1394_IntMaskClear, OHCI1394_busReset);
+#endif		
+		spin_unlock_irqrestore(&ohci->event_lock, flags);
 		if (!host->in_bus_reset) {
 			DBGMSG(ohci->id, "irq_handler: Bus reset requested%s",
 			      ((host->attempt_root || attempt_root) ?
 			      " and attempting to become root" : ""));
-			
-			/* Wait for the AT fifo to be flushed */
-			dma_trm_reset(ohci->at_req_context);
-			dma_trm_reset(ohci->at_resp_context);
 
 			/* Subsystem call */
 			hpsb_bus_reset(ohci->host);
-			
-			ohci->NumBusResets++;
 		}
-		/* Mask out everything except selfid */
-		event &= OHCI1394_selfIDComplete;
+		event &= ~OHCI1394_busReset;
 	}
 
 	/* XXX: We need a way to also queue the OHCI1394_reqTxComplete,
@@ -1234,11 +1282,12 @@
 
 				handle_selfid(ohci, host, 
 					      phyid, isroot);
-			} else 
+			} else {
 				PRINT(KERN_ERR, ohci->id, 
 				      "SelfID interrupt received, but "
 				      "NodeID is not valid: %08X",
 				      node_id);
+			}
 
 			/* Accept Physical requests from all nodes. */
 			reg_write(ohci,OHCI1394_AsReqFilterHiSet, 
@@ -1258,21 +1307,15 @@
 			PRINT(KERN_ERR, ohci->id, 
 			      "SelfID received outside of bus reset sequence");
 
-		/* Clear everything, it's a new day */
+		/* Finally, we clear the busReset event and reenable
+		 * the busReset interrupt. */
+#ifndef BUSRESET_WORKAROUND
 		spin_lock_irqsave(&ohci->event_lock, flags);
-		reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
+		reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset); 
+		reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
 		spin_unlock_irqrestore(&ohci->event_lock, flags);
-
-		event &= ~OHCI1394_selfIDComplete;
-	}
-	if (event & OHCI1394_phyRegRcvd) {
-		if (host->in_bus_reset) {
-			DBGMSG (ohci->id, "PhyControl: %08X", 
-				reg_read(ohci, OHCI1394_PhyControl));
-		} else
-			PRINT(KERN_ERR, ohci->id, 
-			      "Physical register received outside of bus reset sequence");
-		event &= ~OHCI1394_phyRegRcvd;
+#endif
+		event &= ~OHCI1394_selfIDComplete;	
 	}
 
 	/* Make sure we handle everything, just in case we accidentally
@@ -1365,14 +1408,14 @@
 	dma_cache_wback_inv(buf_ptr, bytes_left);
 
 	while (bytes_left > 0) {
-		tcode = (cond_le32_to_cpu(buf_ptr[0], ohci->payload_swap) >> 4) & 0xf;
+		tcode = (cond_le32_to_cpu(buf_ptr[0], ohci->no_swap_incoming) >> 4) & 0xf;
 
 		/* packet_length() will return < 4 for an error */
-		length = packet_length(d, idx, buf_ptr, offset, tcode, ohci->payload_swap);
+		length = packet_length(d, idx, buf_ptr, offset, tcode, ohci->no_swap_incoming);
 
 		if (length < 4) { /* something is wrong */
 			sprintf(msg,"Unexpected tcode 0x%x(0x%08x) in AR ctx=%d, length=%d",
-				tcode, cond_le32_to_cpu(buf_ptr[0], ohci->payload_swap),
+				tcode, cond_le32_to_cpu(buf_ptr[0], ohci->no_swap_incoming),
 				d->ctx, length);
 			ohci1394_stop_context(ohci, d->ctrlClear, msg);
 			spin_unlock_irqrestore(&d->lock, flags);
@@ -1448,19 +1491,18 @@
 		/* We get one phy packet to the async descriptor for each
 		 * bus reset. We always ignore it.  */
 		if (tcode != OHCI1394_TCODE_PHY) {
-			if (!ohci->payload_swap)
-				packet_swab(d->spb, tcode, (length - 4) >> 2, 0);
-
+			if (!ohci->no_swap_incoming)
+				packet_swab(d->spb, tcode, (length - 4) >> 2);
 			DBGMSG(ohci->id, "Packet received from node"
 				" %d ack=0x%02X spd=%d tcode=0x%X"
 				" length=%d ctx=%d tlabel=%d",
 				(d->spb[1]>>16)&0x3f,
-				(cond_le32_to_cpu(d->spb[length/4-1], ohci->payload_swap)>>16)&0x1f,
-				(cond_le32_to_cpu(d->spb[length/4-1], ohci->payload_swap)>>21)&0x3,
+				(cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f,
+				(cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>21)&0x3,
 				tcode, length, d->ctx,
-				(cond_le32_to_cpu(d->spb[length/4-1], ohci->payload_swap)>>10)&0x3f);
+				(cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>10)&0x3f);
 
-			ack = (((cond_le32_to_cpu(d->spb[length/4-1], ohci->payload_swap)>>16)&0x1f)
+			ack = (((cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f)
 				== 0x11) ? 1 : 0;
 
 			hpsb_packet_received(ohci->host, d->spb, 
@@ -1510,7 +1552,7 @@
 	while (d->fifo_first) {
 		packet = d->fifo_first;
                 datasize = d->fifo_first->data_size;
-		if (datasize && packet->type != raw)
+		if (datasize && packet->type != hpsb_raw)
 			ack = le32_to_cpu(
 				d->prg_cpu[d->sent_ind]->end.status) >> 16;
 		else 
@@ -2032,6 +2074,14 @@
 	hw_csr_reg:		ohci_hw_csr_reg,
 };
 
+
+#define FAIL(fmt, args...)			\
+do {						\
+	PRINT_G(KERN_ERR, fmt , ## args);	\
+	remove_card(ohci);			\
+	return 1;				\
+} while(0)
+
 static int __devinit ohci1394_add_one(struct pci_dev *dev, const struct pci_device_id *ent)
 {
 	struct ti_ohci *ohci;	/* shortcut to currently handled device */
@@ -2075,10 +2125,10 @@
 	 * noByteSwapData registers to see if they were not cleared to
 	 * zero. Should this work? Obviously it's not defined what these
 	 * registers will read when they aren't supported. Bleh! */
-	if (dev->vendor == PCI_VENDOR_ID_APPLE) {
-		ohci->payload_swap = 1;
-		if (dev->device != PCI_DEVICE_ID_APPLE_UNI_N_FW)
-			ohci->selfid_swap = 1;
+	if (dev->vendor == PCI_VENDOR_ID_APPLE && 
+		dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) {
+			ohci->no_swap_incoming = 1;
+			ohci->selfid_swap = 0;
 	} else
 		ohci->selfid_swap = 1;
 #endif
@@ -2248,6 +2298,23 @@
 	release_mem_region (pci_resource_start(ohci->dev, 0),
 			    pci_resource_len(ohci->dev, 0));
 
+#ifdef CONFIG_ALL_PPC
+	/* On UniNorth, power down the cable and turn off the
+	 * chip clock when the module is removed to save power
+	 * on laptops. Turning it back ON is done by the arch
+	 * code when pci_enable_device() is called
+	 */
+	{
+		struct device_node* of_node;
+
+		of_node = pci_device_to_OF_node(ohci->dev);
+		if (of_node) {
+			feature_set_firewire_power(of_node, 0);
+			feature_set_firewire_cable_power(of_node, 0);
+		}
+	}
+#endif /* CONFIG_ALL_PPC */
+
 	pci_set_drvdata(ohci->dev, NULL);
 }
 
@@ -2291,68 +2358,6 @@
 		MOD_DEC_USE_COUNT;
 	}
 }
-
-#ifndef __LITTLE_ENDIAN
-
-/* Swap a series of quads inplace. */
-static __inline__ void block_swab32(quadlet_t *data, size_t size) {
-	while (size--)
-		data[size] = swab32(data[size]);
-}
-
-/* Swap headers and sometimes data too */
-static void packet_swab(quadlet_t *data, char tcode, int len, int payload_swap)
-{
-	if (payload_swap) {
-		block_swab32(data, len);
-		return;
-	}
-
-        switch(tcode)
-        {
-		/* 4 quad header */
-		case TCODE_READB_RESPONSE:
-		case TCODE_LOCK_RESPONSE:
-		case TCODE_LOCK_REQUEST:
-		case TCODE_WRITEB:
-		case TCODE_READB:
-			block_swab32(data, 4);
-			break;
-
-		/* 3 quad header, 1 quad payload */
-		case TCODE_WRITEQ:
-		case TCODE_READQ_RESPONSE:
-			block_swab32(data, 3);
-			break;
-
-		/* 3 quad header */
-		case TCODE_WRITE_RESPONSE:
-		case TCODE_READQ:
-			block_swab32(data, 3);
-			break;
-
-		/* 2 quad header */
-		case TCODE_ISO_DATA:
-			block_swab32(data, 2);
-			break;
-
-		case OHCI1394_TCODE_PHY:
-			break; /* should never happen anyway */
-
-		case TCODE_CYCLE_START:
-			PRINT_G(KERN_ERR, "Unhandled tcode in packet_swab (0x%x)", tcode);
-			/* Atleast swap one quad */
-			block_swab32(data, 1);
-			break;
-                default:
-			PRINT_G(KERN_ERR, "Invalid tcode in packet_swab (0x%x)", tcode);
-                        break;
-        }
-	return;
-}
-
-#endif /* !LITTLE_ENDIAN */
-
 
 #if 0
 int ohci1394_request_channel(struct ti_ohci *ohci, int channel)
diff -urN linux-2.4.11-pre2/drivers/ieee1394/ohci1394.h linux/drivers/ieee1394/ohci1394.h
--- linux-2.4.11-pre2/drivers/ieee1394/ohci1394.h	Sun Aug 12 12:39:02 2001
+++ linux/drivers/ieee1394/ohci1394.h	Mon Dec  3 23:15:39 2001
@@ -191,15 +191,14 @@
 	spinlock_t event_lock;
 
 	int self_id_errors;
-        int NumBusResets;
 
 	/* video device */
 	struct video_template *video_tmpl;
 
 	/* Swap the selfid buffer? */
 	unsigned int selfid_swap:1;
-	/* Swap the payload? */
-	unsigned int payload_swap:1;
+	/* Some Apple chipset seem to swap incoming headers for us */
+	unsigned int no_swap_incoming:1;
 };
 
 static inline int cross_bound(unsigned long addr, unsigned int size)
@@ -332,14 +331,16 @@
 #define OHCI1394_phyRegRcvd              0x04000000
 #define OHCI1394_masterIntEnable         0x80000000
 
-#define OUTPUT_MORE                      0x00000000
-#define OUTPUT_MORE_IMMEDIATE            0x02000000
-#define OUTPUT_LAST                      0x103c0000
-#define OUTPUT_LAST_IMMEDIATE            0x123c0000
-
-#define DMA_SPEED_100                    0x0
-#define DMA_SPEED_200                    0x1
-#define DMA_SPEED_400                    0x2
+/* DMA Control flags */
+#define DMA_CTL_OUTPUT_MORE              0x00000000
+#define DMA_CTL_OUTPUT_LAST              0x10000000
+#define DMA_CTL_INPUT_MORE               0x20000000
+#define DMA_CTL_INPUT_LAST               0x30000000
+#define DMA_CTL_UPDATE                   0x08000000
+#define DMA_CTL_IMMEDIATE                0x02000000
+#define DMA_CTL_IRQ                      0x00300000
+#define DMA_CTL_BRANCH                   0x000c0000
+#define DMA_CTL_WAIT                     0x00030000
 
 #define OHCI1394_TCODE_PHY               0xE
 
diff -urN linux-2.4.11-pre2/drivers/ieee1394/pcilynx.c linux/drivers/ieee1394/pcilynx.c
--- linux-2.4.11-pre2/drivers/ieee1394/pcilynx.c	Mon Dec  3 23:15:29 2001
+++ linux/drivers/ieee1394/pcilynx.c	Mon Dec  3 23:15:39 2001
@@ -38,6 +38,7 @@
 #include "ieee1394_types.h"
 #include "hosts.h"
 #include "ieee1394_core.h"
+#include "highlevel.h"
 #include "pcilynx.h"
 
 
@@ -393,7 +394,7 @@
         struct lynx_send_data *d;
         struct hpsb_packet *packet;
 
-        d = (what == iso ? &lynx->iso_send : &lynx->async);
+        d = (what == hpsb_iso ? &lynx->iso_send : &lynx->async);
         packet = d->queue;
 
         d->header_dma = pci_map_single(lynx->dev, packet->header,
@@ -419,13 +420,13 @@
         pcl.buffer[1].pointer = d->data_dma;
 
         switch (packet->type) {
-        case async:
+        case hpsb_async:
                 pcl.buffer[0].control |= PCL_CMD_XMT;
                 break;
-        case iso:
+        case hpsb_iso:
                 pcl.buffer[0].control |= PCL_CMD_XMT | PCL_ISOMODE;
                 break;
-        case raw:
+        case hpsb_raw:
                 pcl.buffer[0].control |= PCL_CMD_UNFXMT;
                 break;
         }                
@@ -606,11 +607,11 @@
         }
 
         switch (packet->type) {
-        case async:
-        case raw:
+        case hpsb_async:
+        case hpsb_raw:
                 d = &lynx->async;
                 break;
-        case iso:
+        case hpsb_iso:
                 d = &lynx->iso_send;
                 break;
         default:
@@ -1227,7 +1228,7 @@
                 }
 
                 if (lynx->async.queue != NULL) {
-                        send_next(lynx, async);
+                        send_next(lynx, hpsb_async);
                 }
 
                 spin_unlock(&lynx->async.queue_lock);
@@ -1259,7 +1260,7 @@
                 }
 
                 if (lynx->iso_send.queue != NULL) {
-                        send_next(lynx, iso);
+                        send_next(lynx, hpsb_iso);
                 }
 
                 spin_unlock(&lynx->iso_send.queue_lock);
@@ -1368,7 +1369,7 @@
                 FAIL("failed to allocate host structure");
 
         lynx->state = have_host_struct;
-
+	lynx->host->hostdata = lynx;
         lynx->id = num_of_cards-1;
         lynx->dev = dev;
 	lynx->host->pdev = dev;
@@ -1501,6 +1502,9 @@
                 PRINT(KERN_INFO, lynx->id, "found old 1394 PHY");
         }
 
+	/* Tell the highlevel this host is ready */
+	highlevel_add_one_host (lynx->host);
+
         return 0;
 #undef FAIL
 }
@@ -1633,8 +1637,8 @@
 
 static void __exit pcilynx_cleanup(void)
 {
-        pci_unregister_driver(&lynx_pcidriver);
         hpsb_unregister_lowlevel(&lynx_template);
+	pci_unregister_driver(&lynx_pcidriver);
         PRINT_G(KERN_INFO, "removed " PCILYNX_DRIVER_NAME " module");
 }
 
diff -urN linux-2.4.11-pre2/drivers/ieee1394/raw1394.c linux/drivers/ieee1394/raw1394.c
--- linux-2.4.11-pre2/drivers/ieee1394/raw1394.c	Mon Dec  3 23:15:29 2001
+++ linux/drivers/ieee1394/raw1394.c	Mon Dec  3 23:15:39 2001
@@ -290,8 +290,11 @@
         }
         spin_unlock_irqrestore(&host_info_lock, flags);
 
-        list_for_each(lh, &reqs) {
+        lh = reqs.next;
+        while (lh != &reqs) {
                 req = list_entry(lh, struct pending_request, list);
+                lh = lh->next;
+
                 queue_complete_req(req);
         }
 }
@@ -356,8 +359,11 @@
         }
         spin_unlock_irqrestore(&host_info_lock, flags);
 
-        list_for_each(lh, &reqs) {
+        lh = reqs.next;
+        while (lh != &reqs) {
                 req = list_entry(lh, struct pending_request, list);
+                lh = lh->next;
+
                 queue_complete_req(req);
         }
 }
@@ -746,6 +752,8 @@
         list_add_tail(&req->list, &fi->req_pending);
         spin_unlock_irq(&fi->reqlists_lock);
 
+	packet->generation = req->req.generation;
+
         if (!hpsb_send_packet(packet)) {
                 req->req.error = RAW1394_ERROR_SEND_ERROR;
                 req->req.length = 0;
@@ -766,7 +774,7 @@
 
         fill_iso_packet(packet, req->req.length, channel & 0x3f,
                         (req->req.misc >> 16) & 0x3, req->req.misc & 0xf);
-        packet->type = iso;
+        packet->type = hpsb_iso;
         packet->speed_code = req->req.address & 0x3;
         packet->host = fi->host;
 
@@ -786,6 +794,9 @@
         spin_lock_irq(&fi->reqlists_lock);
         list_add_tail(&req->list, &fi->req_pending);
         spin_unlock_irq(&fi->reqlists_lock);
+
+	/* Update the generation of the packet just before sending. */
+	packet->generation = get_hpsb_generation(fi->host);
 
         if (!hpsb_send_packet(packet)) {
                 req->req.error = RAW1394_ERROR_SEND_ERROR;
diff -urN linux-2.4.11-pre2/drivers/ieee1394/sbp2.c linux/drivers/ieee1394/sbp2.c
--- linux-2.4.11-pre2/drivers/ieee1394/sbp2.c	Thu Aug 16 09:49:49 2001
+++ linux/drivers/ieee1394/sbp2.c	Mon Dec  3 23:15:39 2001
@@ -122,26 +122,14 @@
  *	  are some stress issues under investigation with deserialized I/O. To enable
  *	  deserialized I/O for testing, do "insmod sbp2 serialize_io=0"
  *
- *	- Hot-Plugging: Need to add procfs support and integration with linux
- *	  hot-plug support (http://linux-hotplug.sourceforge.net) for auto-mounting 
- *	  of drives.
- *
  *	- Error Handling: SCSI aborts and bus reset requests are handled somewhat
  *	  but the code needs additional debugging.
  *
- *	- IEEE-1394 Bus Management: There is currently little bus management
- *	  in the core IEEE-1394 stack. Because of this, the SBP-2 driver handles
- *	  detection of SBP-2 devices itself. This should be moved to the core
- *	  stack.
- *
  *	- The SBP-2 driver is currently only supported as a module. It would not take
  *	  much work to allow it to be compiled into the kernel, but you'd have to 
  *	  add some init code to the kernel to support this... and modules are much
  *	  more flexible anyway.   ;-)
  *
- *	- Workaround for PPC pismo firewire chipset (enable SBP2_PPC_PISMO_WORKAROUND
- *	  define below).
- *
  *
  * History:
  *
@@ -222,8 +210,18 @@
  *							 <bcollins@debian.org
  *	07/22/01 - Use NodeMngr to get info about the local host and
  *		   attached devices. Ben Collins
+ *
+ *      09/15/01 - Remove detection code, instead subscribe to the nodemgr
+ *                 driver management interface.  This also removes the
+ *                 initial bus scan stuff since the nodemgr calls
+ *                 sbp2_probe for each sbp2 device already on the bus,
+ *                 when we register our driver.  This change 
+ *                 automtically adds hotplug support to the driver.
+ *                                 Kristian Hogsberg <hogsberg@users.sf.net>
  */
     
+
+
 /*
  * Includes
  */
@@ -264,50 +262,26 @@
 #include "sbp2.h"
 
 /*
- * PPC firewire Pismo chipset workaround!!!
- *
- * This is a workaround for a bug in the firewire pismo chipset. For some odd reason the status
- * fifo address hi/lo must be byteswapped and the response address byteswapped, but no other
- * parts of the structure. Apple's drivers seem to specifically check for the pismo and do
- * the same workaround for sbp2. (Daniel Berlin)
- *
- * Please enable the following define if you're running on the PPC Pismo chipset.
- */
-
-#ifdef CONFIG_IEEE1394_SBP2_PISMO
-#define SBP2_NEED_LOGIN_DESCRIPTOR_WORKAROUND
-#endif
-
-/*
  * Module load parameter definitions
  */
 
 /*
- * Normally the sbp2 driver tries to catch the initial scsi bus scan to pick up any 
- * attached sbp2 devices. Setting no_bus_scan to 1 tells the sbp2 driver not to catch
- * this initial scsi bus scan on module load. You can always either add or remove devices 
- * later through the rescan-scsi-bus.sh script or scsi procfs.
- */
-MODULE_PARM(no_bus_scan,"i");
-MODULE_PARM_DESC(no_bus_scan, "Skip the initial scsi bus scan during module load");
-static int no_bus_scan = 0;
-
-/*
- * Set mode_sense_hack to 1 if you have some sort of unusual sbp2 device, like a 1394 memory 
- * stick reader, compact flash reader, or MO drive that does not support mode sense. Allows
- * you to mount the media rw instead of ro.
+ * Set mode_sense_hack to 1 if you have some sort of unusual sbp2 device,
+ * like a 1394 memory stick reader, compact flash reader, or MO drive that
+ * does not support mode sense. Allows you to mount the media rw instead
+ * of ro.
  */
 MODULE_PARM(mode_sense_hack,"i");
 MODULE_PARM_DESC(mode_sense_hack, "Emulate mode sense for devices like 1394 memory stick readers");
 static int mode_sense_hack = 0;
 
 /*
- * Change max_speed on module load if you have a bad IEEE-1394 controller that has trouble running
- * 2KB packets at 400mb.
+ * Change max_speed on module load if you have a bad IEEE-1394 controller
+ * that has trouble running 2KB packets at 400mb.
  *
- * NOTE: On certain OHCI parts I have seen short packets on async transmit (probably 
- * due to PCI latency/throughput issues with the part). You can bump down the speed if
- * you are running into problems.
+ * NOTE: On certain OHCI parts I have seen short packets on async transmit
+ * (probably due to PCI latency/throughput issues with the part). You can
+ * bump down the speed if you are running into problems.
  *
  * Valid values:
  * max_speed = 2 (default: max speed 400mb)
@@ -319,30 +293,37 @@
 static int max_speed = SPEED_400;
 
 /*
- * Set serialize_io to 1 if you'd like only one scsi command sent down to us at a time (debugging).
+ * Set serialize_io to 1 if you'd like only one scsi command sent down to
+ * us at a time (debugging).
  */
 MODULE_PARM(serialize_io,"i");
 MODULE_PARM_DESC(serialize_io, "Serialize all I/O coming down from the scsi drivers (debugging)");
 static int serialize_io = 1;	/* serialize I/O until stress issues are resolved */
 
 /*
- * Set no_large_packets to 1 if you'd like to limit the size of requests sent down to us (normally
- * the sbp2 driver will break up any requests to any individual devices with 128KB transfer size limits).
- * Sets max s/g list elements to 0x1f in size and disables s/g clustering.
+ * Set no_large_packets to 1 if you'd like to limit the size of requests
+ * sent down to us (normally the sbp2 driver will break up any requests to
+ * any individual devices with 128KB transfer size limits).  Sets max s/g
+ * list elements to 0x1f in size and disables s/g clustering.
  */
 MODULE_PARM(no_large_packets,"i");
 MODULE_PARM_DESC(no_large_packets, "Do not allow large transfers from scsi drivers (debugging)");
 static int no_large_packets = 0;
 
 /*
- * Export information about protocols/devices supported by this driver
+ * Export information about protocols/devices supported by this driver.
  */
 static struct ieee1394_device_id sbp2_id_table[] = {
-	IEEE1394_PROTOCOL(SBP2_UNIT_SPEC_ID_ENTRY, SBP2_SW_VERSION_ENTRY),
+	{
+		match_flags:  IEEE1394_MATCH_SPECIFIER_ID |
+		              IEEE1394_MATCH_VERSION,
+		specifier_id: SBP2_UNIT_SPEC_ID_ENTRY & 0xffffff,
+		version:      SBP2_SW_VERSION_ENTRY & 0xffffff
+	},
 	{ }
 };
 
-MODULE_DEVICE_TABLE(ieee1394, sbp2_id_table); 
+MODULE_DEVICE_TABLE(ieee1394, sbp2_id_table);
 
 /*
  * Debug levels, configured via kernel config.
@@ -372,6 +353,7 @@
 #define SBP2_DMA_FREE(fmt, args...)
 #endif
 
+
 #if CONFIG_IEEE1394_SBP2_DEBUG >= 2
 #define SBP2_DEBUG(fmt, args...)	HPSB_ERR(fmt, ## args)	
 #define SBP2_INFO(fmt, args...)		HPSB_ERR(fmt, ## args)	
@@ -392,12 +374,14 @@
 #define SBP2_ERR(fmt, args...)		HPSB_ERR(fmt, ## args)
 
 /*
- * Spinlock debugging stuff. I'm playing it safe until the driver has been debugged on SMP. (JSG)
+ * Spinlock debugging stuff. I'm playing it safe until the driver has been
+ * debugged on SMP. (JSG)
  */
 /* #define SBP2_USE_REAL_SPINLOCKS */
 #ifdef SBP2_USE_REAL_SPINLOCKS
 #define sbp2_spin_lock(lock, flags)	spin_lock_irqsave(lock, flags)	
 #define sbp2_spin_unlock(lock, flags)	spin_unlock_irqrestore(lock, flags);
+static spinlock_t sbp2_host_info_lock = SPIN_LOCK_UNLOCKED;
 #else
 #define sbp2_spin_lock(lock, flags)	do {save_flags(flags); cli();} while (0)	
 #define sbp2_spin_unlock(lock, flags)	do {restore_flags(flags);} while (0)
@@ -411,28 +395,27 @@
 
 static LIST_HEAD(sbp2_host_info_list);
 static int sbp2_host_count = 0;
-static spinlock_t sbp2_host_info_lock = SPIN_LOCK_UNLOCKED;
 
 static struct hpsb_highlevel *sbp2_hl_handle = NULL;
 
 static struct hpsb_highlevel_ops sbp2_hl_ops = {
-	sbp2_add_host,
-	sbp2_remove_host,
-	sbp2_host_reset,
-	NULL,
-	NULL
+	add_host:	sbp2_add_host,
+	remove_host:	sbp2_remove_host,
 };
 
 static struct hpsb_address_ops sbp2_ops = {
-	write: sbp2_handle_status_write,
+	write: sbp2_handle_status_write
 };
 
-#if 0
-static struct hpsb_address_ops sbp2_physdma_ops = {
-	read: sbp2_handle_physdma_read,
-	write: sbp2_handle_physdma_write,
+static struct hpsb_protocol_driver sbp2_driver = {
+	name:		"SBP2 Driver",
+	id_table: 	sbp2_id_table,
+	probe: 		sbp2_probe,
+	disconnect: 	sbp2_disconnect,
+	update: 	sbp2_update
 };
-#endif
+
+
 
 /**************************************
  * General utility functions
@@ -472,108 +455,29 @@
 #endif
 
 /*
- * This function does quadlet sized reads (used by detection code)
- */
-static int sbp2util_read_quadlet(struct sbp2scsi_host_info *hi, nodeid_t node, u64 addr,
-				 quadlet_t *buffer)
-{
-	int retval = 0;
-	int retry_count = 3;
-
-	/*
-	 * Retry a couple times if needed (for slow devices)
-	 */
-	do {
-
-		retval = hpsb_read(hi->host, node, addr, buffer, 4);
-
-		if (retval) {
-			SBP2_DEBUG("sbp2: sbp2util_read_quadlet data packet error");
-			current->state = TASK_INTERRUPTIBLE;
-			schedule_timeout(HZ/50);	/* 20ms delay */
-		}
-
-		retry_count--;
-
-	} while (retval && retry_count);
-
-	return(retval);
-}
-
-/*
- * This function returns the address of the unit directory.
- */
-static int sbp2util_unit_directory(struct sbp2scsi_host_info *hi, nodeid_t node_id, u64 *unit_directory_addr)
-{
-	quadlet_t root_directory_length, current_quadlet;
-	u64 current_addr;
-	int length, i;
-
-	/*
-	 * First, read the first quadlet of the root directory to determine its size
-	 */
-	if (sbp2util_read_quadlet(hi, LOCAL_BUS | node_id, CONFIG_ROM_ROOT_DIR_BASE, 
-				  &root_directory_length)) {
-		SBP2_DEBUG("sbp2: Error reading root directory length - bad status");
-		return(-EIO);   
-	}
-
-	current_addr = CONFIG_ROM_ROOT_DIR_BASE;
-	length = be32_to_cpu(root_directory_length) >> 16;
-
-	/*
-	 * Step through the root directory and look for the "Unit_Directory entry", which
-	 * contains the offset to the unit directory.
-	 */
-	for (i=0; i < length; i++) {
-
-		current_addr += 4;
-
-		if (sbp2util_read_quadlet(hi, LOCAL_BUS | node_id, current_addr, &current_quadlet)) {
-			SBP2_DEBUG("sbp2: Error reading at address 0x%08x%08x - bad status", 
-				   (unsigned int) ((current_addr) >> 32), (unsigned int) ((current_addr) & 0xffffffff));
-			return(-EIO);   
-		}
-
-		/*  
-		 * Check for unit directory offset tag 
-		 */
-		if ((be32_to_cpu(current_quadlet) >> 24) == SBP2_UNIT_DIRECTORY_OFFSET_KEY) {
-			*unit_directory_addr = current_addr + 4 * ((be32_to_cpu(current_quadlet) & 0xffffff));
-			SBP2_DEBUG("sbp2: unit_directory_addr = %lu", *unit_directory_addr);
-		}
-	}
-
-	return(0);
-}
-
-/*
- * This function is called to initially create a packet pool for use in sbp2 I/O requests.
- * This packet pool is used when sending out sbp2 command and agent reset requests, and 
- * allows us to remove all kmallocs/kfrees from the critical I/O paths.
+ * This function is called to initially create a packet pool for use in
+ * sbp2 I/O requests. This packet pool is used when sending out sbp2
+ * command and agent reset requests, and allows us to remove all
+ * kmallocs/kfrees from the critical I/O paths.
  */
 static int sbp2util_create_request_packet_pool(struct sbp2scsi_host_info *hi)
 {
 	struct hpsb_packet *packet;
 	int i;
-	unsigned long flags;
 
-	/*
-	 * Create SBP2_MAX_REQUEST_PACKETS number of request packets.
-	 */
-	sbp2_spin_lock(&hi->sbp2_request_packet_lock, flags);
+	/* Create SBP2_MAX_REQUEST_PACKETS number of request packets. */
 	for (i=0; i<SBP2_MAX_REQUEST_PACKETS; i++) {
 
 		/*
-		 * Max payload of 8 bytes since the sbp2 command request uses a payload of 
-		 * 8 bytes, and agent reset is a quadlet write request. Bump this up if we
-		 * plan on using this pool for other stuff.
+		 * Max payload of 8 bytes since the sbp2 command request
+		 * uses a payload of 8 bytes, and agent reset is a quadlet
+		 * write request. Bump this up if we plan on using this
+		 * pool for other stuff.
 		 */
 		packet = alloc_hpsb_packet(8);
 
 		if (!packet) {
 			SBP2_ERR("sbp2: sbp2util_create_request_packet_pool - packet allocation failed!");
-			sbp2_spin_unlock(&hi->sbp2_request_packet_lock, flags);
 			return(-ENOMEM);
 		}
 
@@ -585,13 +489,13 @@
 		list_add_tail(&hi->request_packet[i].list, &hi->sbp2_req_free);
 
 	}
-	sbp2_spin_unlock(&hi->sbp2_request_packet_lock, flags);
 
 	return(0);
 }
 
 /*
- * This function is called to remove the packet pool. It is called when the sbp2 driver is unloaded.
+ * This function is called to remove the packet pool. It is called when
+ * the sbp2 driver is unloaded.
  */
 static void sbp2util_remove_request_packet_pool(struct sbp2scsi_host_info *hi)
 {
@@ -624,15 +528,17 @@
 }
 
 /*
- * This function is called to retrieve a block write packet from our packet pool. This function is
- * used in place of calling alloc_hpsb_packet (which costs us three kmallocs). Instead we 
- * just pull out a free request packet and re-initialize values in it. I'm sure this can still
- * stand some more optimization. 
- */
-static struct sbp2_request_packet *sbp2util_allocate_write_request_packet(struct sbp2scsi_host_info *hi,
-									  nodeid_t node, u64 addr,
-									  size_t data_size,
-									  quadlet_t data) {
+ * This function is called to retrieve a block write packet from our
+ * packet pool. This function is used in place of calling
+ * alloc_hpsb_packet (which costs us three kmallocs). Instead we just pull
+ * out a free request packet and re-initialize values in it. I'm sure this
+ * can still stand some more optimization.
+ */
+static struct sbp2_request_packet *
+sbp2util_allocate_write_request_packet(struct sbp2scsi_host_info *hi,
+				       nodeid_t node, u64 addr,
+				       size_t data_size,
+				       quadlet_t data) {
 	struct list_head *lh;
 	struct sbp2_request_packet *request_packet = NULL;
 	struct hpsb_packet *packet;
@@ -651,13 +557,14 @@
 		packet = request_packet->packet;
 
 		/*
-		 * Initialize the packet (this is really initialization the core 1394 stack should do,
-		 * but I'm doing it myself to avoid the overhead).
+		 * Initialize the packet (this is really initialization
+		 * the core 1394 stack should do, but I'm doing it myself
+		 * to avoid the overhead).
 		 */
 		packet->data_size = data_size;
 		INIT_LIST_HEAD(&packet->list);
 		sema_init(&packet->state_change, 0);
-		packet->state = unused;
+		packet->state = hpsb_unused;
 		packet->generation = get_hpsb_generation(hi->host);
 		packet->data_be = 1;
 
@@ -672,8 +579,8 @@
 		}
 
 		/*
-		 * Set up a task queue completion routine, which returns the packet to the free list
-		 * and releases the tlabel
+		 * Set up a task queue completion routine, which returns
+		 * the packet to the free list and releases the tlabel.
 		 */
 		request_packet->tq.routine = (void (*)(void*))sbp2util_free_request_packet;
 		request_packet->tq.data = request_packet;
@@ -681,7 +588,7 @@
 		queue_task(&request_packet->tq, &packet->complete_tq);
 
 		/*
-		 * Now, put the packet on the in-use list
+		 * Now, put the packet on the in-use list.
 		 */
 		list_add_tail(&request_packet->list, &hi->sbp2_req_inuse);
 
@@ -694,8 +601,8 @@
 }
 
 /*
- * This function is called to return a packet to our packet pool. It is also called as a 
- * completion routine when a request packet is completed.
+ * This function is called to return a packet to our packet pool. It is
+ * also called as a completion routine when a request packet is completed.
  */
 static void sbp2util_free_request_packet(struct sbp2_request_packet *request_packet)
 {
@@ -703,7 +610,7 @@
 	struct sbp2scsi_host_info *hi = request_packet->hi_context;
 
 	/*
-	 * Free the tlabel, and return the packet to the free pool
+	 * Free the tlabel, and return the packet to the free pool.
 	 */
 	sbp2_spin_lock(&hi->sbp2_request_packet_lock, flags);
 	free_tlabel(hi->host, LOCAL_BUS | request_packet->packet->node_id,
@@ -716,8 +623,8 @@
 }
 
 /*
- * This function is called to create a pool of command orbs used for command processing. It is called
- * when a new sbp2 device is detected.
+ * This function is called to create a pool of command orbs used for
+ * command processing. It is called when a new sbp2 device is detected.
  */
 static int sbp2util_create_command_orb_pool(struct scsi_id_instance_data *scsi_id,
 					    struct sbp2scsi_host_info *hi)
@@ -785,10 +692,11 @@
 }
 
 /* 
- * This functions finds the sbp2_command for a given outstanding
- * command orb. Only looks at the inuse list.
+ * This functions finds the sbp2_command for a given outstanding command
+ * orb. Only looks at the inuse list.
  */
-static struct sbp2_command_info *sbp2util_find_command_for_orb(struct scsi_id_instance_data *scsi_id, dma_addr_t orb)
+static struct sbp2_command_info *sbp2util_find_command_for_orb(
+		struct scsi_id_instance_data *scsi_id, dma_addr_t orb)
 {
 	struct list_head *lh;
 	struct sbp2_command_info *command;
@@ -812,7 +720,8 @@
 }
 
 /* 
- * This functions finds the sbp2_command for a given outstanding SCpnt. Only looks at the inuse list 
+ * This functions finds the sbp2_command for a given outstanding SCpnt.
+ * Only looks at the inuse list.
  */
 static struct sbp2_command_info *sbp2util_find_command_for_SCpnt(struct scsi_id_instance_data *scsi_id, void *SCpnt)
 {
@@ -837,10 +746,11 @@
 /*
  * This function allocates a command orb used to send a scsi command.
  */
-static struct sbp2_command_info *sbp2util_allocate_command_orb(struct scsi_id_instance_data *scsi_id, 
-							       Scsi_Cmnd *Current_SCpnt, 
-							       void (*Current_done)(Scsi_Cmnd *),
-							       struct sbp2scsi_host_info *hi)
+static struct sbp2_command_info *sbp2util_allocate_command_orb(
+		struct scsi_id_instance_data *scsi_id, 
+		Scsi_Cmnd *Current_SCpnt, 
+		void (*Current_done)(Scsi_Cmnd *),
+		struct sbp2scsi_host_info *hi)
 {
 	struct list_head *lh;
 	struct sbp2_command_info *command = NULL;
@@ -903,13 +813,15 @@
 	sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags);
 }
 
+
+
 /*********************************************
  * IEEE-1394 core driver stack related section
  *********************************************/
 
 /*
- * This function is called at SCSI init in order to register our driver with the
- * IEEE-1394 stack
+ * This function is called at SCSI init in order to register our driver
+ * with the IEEE-1394 stack.
  */
 int sbp2_init(void)
 {
@@ -931,26 +843,21 @@
 	hpsb_register_addrspace(sbp2_hl_handle, &sbp2_ops, SBP2_STATUS_FIFO_ADDRESS,
 				SBP2_STATUS_FIFO_ADDRESS + sizeof(struct sbp2_status_block));
 
-	/*
-	 * Register physical dma address space... used for
-	 * adapters not supporting hardware phys dma.
-	 *
-	 * XXX: Disabled for now.
-	 */
-	/* hpsb_register_addrspace(sbp2_hl_handle, &sbp2_physdma_ops,
-				   0x0ULL, 0xfffffffcULL); */
+	hpsb_register_protocol(&sbp2_driver);
 
-	return(0);
+	return 0;
 }
 
 /*
- * This function is called from cleanup module, or during shut-down, in order to 
- * unregister our driver
+ * This function is called from cleanup module, or during shut-down, in
+ * order to unregister our driver.
  */
 void sbp2_cleanup(void)
 {
 	SBP2_DEBUG("sbp2: sbp2_cleanup");
 
+	hpsb_unregister_protocol(&sbp2_driver);
+
 	if (sbp2_hl_handle) {
 		hpsb_unregister_highlevel(sbp2_hl_handle);
 		sbp2_hl_handle = NULL;
@@ -958,73 +865,121 @@
 	return;
 }
 
-/*
- * This function is called after registering our operations in sbp2_init. We go ahead and
- * allocate some memory for our host info structure, and init some structures.
- */
-static void sbp2_add_host(struct hpsb_host *host)
+static int sbp2_probe(struct unit_directory *ud)
 {
 	struct sbp2scsi_host_info *hi;
-	unsigned long flags;
 
-	SBP2_DEBUG("sbp2: sbp2_add_host");
+	SBP2_DEBUG("sbp2: sbp2_probe");
+	hi = sbp2_find_host_info(ud->ne->host);
 
-	/*
-	 * Allocate some memory for our host info structure
-	 */
-	hi = (struct sbp2scsi_host_info *)kmalloc(sizeof(struct sbp2scsi_host_info), GFP_KERNEL);
+	return sbp2_start_device(hi, ud);
+}
 
-	if (hi != NULL) {
+static void sbp2_disconnect(struct unit_directory *ud)
+{
+	struct sbp2scsi_host_info *hi;
+	struct scsi_id_instance_data *scsi_id = ud->driver_data;
 
-		/*
-		 * Initialize some host stuff
-		 */
-		memset(hi, 0, sizeof(struct sbp2scsi_host_info));
-		INIT_LIST_HEAD(&hi->list);
-		INIT_LIST_HEAD(&hi->sbp2_req_inuse);
-		INIT_LIST_HEAD(&hi->sbp2_req_free);
-		hi->host = host;
-		hi->sbp2_command_lock = SPIN_LOCK_UNLOCKED;
-		hi->sbp2_request_packet_lock = SPIN_LOCK_UNLOCKED;
+	SBP2_DEBUG("sbp2: sbp2_disconnect");
+	hi = sbp2_find_host_info(ud->ne->host);
 
-		/*
-		 * Create our request packet pool (pool of packets for use in I/O)
+	if (hi != NULL)
+		sbp2_remove_device(hi, scsi_id);
+}
+
+static void sbp2_update(struct unit_directory *ud)
+{
+	struct sbp2scsi_host_info *hi;
+	struct scsi_id_instance_data *scsi_id = ud->driver_data;
+	unsigned long flags;
+
+	SBP2_DEBUG("sbp2: sbp2_update");
+	hi = sbp2_find_host_info(ud->ne->host);
+
+	if (sbp2_reconnect_device(hi, scsi_id)) {
+		
+		/* Ok, reconnect has failed.  Perhaps we didn't
+		 * reconnect fast enough. Try doing a regular login.
 		 */
-		if (sbp2util_create_request_packet_pool(hi)) {
-			SBP2_ERR("sbp2: sbp2util_create_request_packet_pool failed!");
+		if (sbp2_login_device(hi, scsi_id)) {
+
+			/* Login failed too... so, just mark him as
+			 * unvalidated, so that he gets cleaned up
+			 * later.
+			 */
+			SBP2_ERR("sbp2: sbp2_reconnect_device failed!");
+			sbp2_remove_device(hi, scsi_id);
 			return;
 		}
+	}
 
-		sbp2_spin_lock(&sbp2_host_info_lock, flags);
-		list_add_tail(&hi->list, &sbp2_host_info_list);
-		sbp2_host_count++;
-		sbp2_spin_unlock(&sbp2_host_info_lock, flags);
+	/* Set max retries to something large on the device. */
+	sbp2_set_busy_timeout(hi, scsi_id);
 
-		/*
-		 * Initialize us to bus reset in progress
-		 */
-		hi->bus_reset_in_progress = 1;
+	/* Do a SBP-2 fetch agent reset. */
+	sbp2_agent_reset(hi, scsi_id, 0);
+	
+	/* Get the max speed and packet size that we can use. */
+	sbp2_max_speed_and_size(hi, scsi_id);
 
-		/*
-		 * Register our host with the SCSI stack. 
-		 */
-		sbp2scsi_register_scsi_host(hi);
+	/* Complete any pending commands with busy (so they get
+	 * retried) and remove them from our queue
+	 */
+	sbp2_spin_lock(&hi->sbp2_command_lock, flags);
+	sbp2scsi_complete_all_commands(hi, scsi_id, DID_BUS_BUSY);
+	sbp2_spin_unlock(&hi->sbp2_command_lock, flags);
+}
 
-		/*
-		 * Start our kernel thread to deal with sbp2 device detection
-		 */
-		init_waitqueue_head(&hi->sbp2_detection_wait);
-		hi->sbp2_detection_pid = 0;
-		hi->sbp2_detection_pid = kernel_thread(sbp2_detection_thread, hi, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+/*
+ * This function is called after registering our operations in sbp2_init.
+ * We go ahead and allocate some memory for our host info structure, and
+ * init some structures.
+ */
+static void sbp2_add_host(struct hpsb_host *host)
+{
+	struct sbp2scsi_host_info *hi;
+	unsigned long flags;
+
+	SBP2_DEBUG("sbp2: sbp2_add_host");
+
+	/* Allocate some memory for our host info structure */
+	hi = (struct sbp2scsi_host_info *)kmalloc(sizeof(struct sbp2scsi_host_info),
+						  GFP_KERNEL);
 
+	if (hi == NULL) {
+		SBP2_ERR("sbp2: out of memory in sbp2_add_host");
+		return;
+	}
+
+	/* Initialize some host stuff */
+	memset(hi, 0, sizeof(struct sbp2scsi_host_info));
+	INIT_LIST_HEAD(&hi->list);
+	INIT_LIST_HEAD(&hi->sbp2_req_inuse);
+	INIT_LIST_HEAD(&hi->sbp2_req_free);
+	hi->host = host;
+	hi->sbp2_command_lock = SPIN_LOCK_UNLOCKED;
+	hi->sbp2_request_packet_lock = SPIN_LOCK_UNLOCKED;
+
+	/* Create our request packet pool (pool of packets for use in I/O) */
+	if (sbp2util_create_request_packet_pool(hi)) {
+		SBP2_ERR("sbp2: sbp2util_create_request_packet_pool failed!");
+		return;
 	}
 
+	sbp2_spin_lock(&sbp2_host_info_lock, flags);
+	list_add_tail(&hi->list, &sbp2_host_info_list);
+	sbp2_host_count++;
+	sbp2_spin_unlock(&sbp2_host_info_lock, flags);
+
+	/* Register our host with the SCSI stack. */
+	sbp2scsi_register_scsi_host(hi);
+
 	return;
 }
 
 /*
- * This fuction returns a host info structure from the host structure,
- * in case we have multiple hosts
+ * This fuction returns a host info structure from the host structure, in
+ * case we have multiple hosts.
  */
 static struct sbp2scsi_host_info *sbp2_find_host_info(struct hpsb_host *host)
 {
@@ -1047,206 +1002,55 @@
 static void sbp2_remove_host(struct hpsb_host *host)
 {
 	struct sbp2scsi_host_info *hi;
-	int i;
 	unsigned long flags;
+	int i;
 
 	SBP2_DEBUG("sbp2: sbp2_remove_host");
 
 	sbp2_spin_lock(&sbp2_host_info_lock, flags);
-	hi = sbp2_find_host_info(host);
 
+	hi = sbp2_find_host_info(host);
 	if (hi != NULL) {
-
-		/*
-		 * Need to remove any attached SBP-2 devices. Also make sure to logout of all devices.
+		/* Here's an annoying hack: we get a disconnect
+		 * callback for each device, so this loop shouldn't be
+		 * necessary.  However, the sbp2 driver receives the
+		 * remove_host callback before the nodemgr, so when we
+		 * get the disconnect callback, we've already freed
+		 * the host.  Thus, we free the devices here...
 		 */
-		for (i=0; i<SBP2SCSI_MAX_SCSI_IDS; i++) {
-			if (hi->scsi_id[i]) {
+		for (i = 0; i < SBP2SCSI_MAX_SCSI_IDS; i++) {
+			if (hi->scsi_id[i] != NULL) {
 				sbp2_logout_device(hi, hi->scsi_id[i]);
-				hi->scsi_id[i]->validated = 0;
+				sbp2_remove_device(hi, hi->scsi_id[i]);
 			}
 		}
-
-		sbp2_remove_unvalidated_devices(hi);
-
-		list_del(&hi->list);
+		sbp2util_remove_request_packet_pool(hi);
 		sbp2_host_count--;
+		list_del(&hi->list);
+		kfree(hi);
 	}
-	sbp2_spin_unlock(&sbp2_host_info_lock, flags);
-
-	if (hi == NULL) {
+	else
 		SBP2_ERR("sbp2: attempt to remove unknown host %p", host);
-		return;
-	}
-
-	/*
-	 * Remove the packet pool (release the packets)
-	 */
-	sbp2util_remove_request_packet_pool(hi);
-
-	/* 
-	 * Kill our detection thread 
-	 */
-	if (hi->sbp2_detection_pid >= 0) {
-		kill_proc(hi->sbp2_detection_pid, SIGINT, 1);
-	}
-
-	/*
-	 * Give the detection thread a little time to exit
-	 */
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(HZ);	/* 1 second delay */
-
-	kfree(hi);
-	hi = NULL;
-
-	return;
-}
 
-/*
- * This is our sbp2 detection thread. It is signalled when bus resets occur
- * so that we can find and initialize any sbp2 devices. 
- */
-static int sbp2_detection_thread(void *__hi)
-{
-	struct sbp2scsi_host_info *hi = (struct sbp2scsi_host_info *)__hi;
-
-	SBP2_DEBUG("sbp2: sbp2_detection_thread");
-
-	lock_kernel();
-
-	/*
-	 * This thread doesn't need any user-level access,
-	 * so get rid of all our resources
-	 */
-#if LINUX_VERSION_CODE > 0x20300
-	daemonize();
-#endif
-
-	/* 
-	 * Set-up a nice name
-	 */
-	strcpy(current->comm, SBP2_DEVICE_NAME);
-
-	unlock_kernel();
-        
-	while ((!signal_pending(current)) && hi) {
-
-		/*
-		 * Process our bus reset now
-		 */
-		if (hi) {
-			MOD_INC_USE_COUNT;
-			sbp2_bus_reset_handler(hi);
-			MOD_DEC_USE_COUNT;
-		}
-
-		/*
-		 * Sleep until next bus reset
-		 */
-		if (hi) {
-			interruptible_sleep_on(&hi->sbp2_detection_wait);
-		}
-	}
-
-	return(0);
+	sbp2_spin_unlock(&sbp2_host_info_lock, flags);
 }
 
 /*
- * This function is where we first pull the node unique ids, and then allocate memory and register
- * a SBP-2 device
+ * This function is where we first pull the node unique ids, and then
+ * allocate memory and register a SBP-2 device.
  */
-static int sbp2_start_device(struct sbp2scsi_host_info *hi, int node_id)
+static int sbp2_start_device(struct sbp2scsi_host_info *hi, struct unit_directory *ud)
 {
-	u64 node_unique_id;
 	struct scsi_id_instance_data *scsi_id = NULL;
 	struct node_entry *ne;
 	int i;
 
 	SBP2_DEBUG("sbp2: sbp2_start_device");
-
-	/* XXX: This will go away once we start using the nodemgr's
-	 * feature subscription API.  */
-	ne = hpsb_nodeid_get_entry(node_id|(hi->host->node_id & BUS_MASK));
-	if (!ne) {
-		HPSB_ERR("sbp2: Could not find device node");
-		return -ENXIO;
-	}
-
-	node_unique_id = ne->guid;
+	ne = ud->ne;
 
 	/*
-	 * First, we need to find out whether this is a "new" SBP-2 device plugged in, or one that already
-	 * exists and is initialized. We do this by looping through our scsi id instance data structures
-	 * looking for matching node unique ids.
-	 */
-	for (i=0; i<SBP2SCSI_MAX_SCSI_IDS; i++) {
-
-		if (hi->scsi_id[i]) {
-
-			if (hi->scsi_id[i]->node_unique_id == node_unique_id) {
-
-				/*
-				 * Update our node id
-				 */
-				hi->scsi_id[i]->node_id = node_id;
-
-				/*
-				 * Mark the device as validated, since it still exists on the bus
-				 */
-				hi->scsi_id[i]->validated = 1;
-				SBP2_DEBUG("sbp2: SBP-2 device re-validated, SCSI ID = %x", (unsigned int) i);
-
-				/*
-				 * Reconnect to the sbp-2 device
-				 */
-				if (sbp2_reconnect_device(hi, hi->scsi_id[i])) {
-
-					/*
-					 * Ok, reconnect has failed. Perhaps we didn't reconnect fast enough. Try
-					 * doing a regular login.
-					 */
-					if (sbp2_login_device(hi, hi->scsi_id[i])) {
-
-						/*
-						 * Login failed too... so, just mark him as unvalidated, so that he gets cleaned up
-						 * later
-						 */
-						SBP2_ERR("sbp2: sbp2_reconnect_device failed!");
-						hi->scsi_id[i]->validated = 0;
-					}
-				}
-
-				if (hi->scsi_id[i]->validated) {
-
-					/*
-					 * Set max retries to something large on the device
-					 */
-					sbp2_set_busy_timeout(hi, hi->scsi_id[i]);
-
-					/*
-					 * Do a SBP-2 fetch agent reset
-					 */
-					sbp2_agent_reset(hi, hi->scsi_id[i], 0);
-
-					/*
-					 * Get the max speed and packet size that we can use
-					 */
-					sbp2_max_speed_and_size(hi, hi->scsi_id[i]);
-
-				}
-
-				/*
-				 * Nothing more to do, since we found the device
-				 */
-				return(0);
-
-			}
-		}
-	}
-
-	/*
-	 * This really is a "new" device plugged in. Let's allocate memory for our scsi id instance data
+	 * This really is a "new" device plugged in. Let's allocate memory
+	 * for our scsi id instance data.
 	 */
 	scsi_id = (struct scsi_id_instance_data *)kmalloc(sizeof(struct scsi_id_instance_data),
 							  GFP_KERNEL);
@@ -1292,509 +1096,195 @@
 			SBP2_DMA_FREE("logout ORB DMA");
 		}
 
-		if (scsi_id->reconnect_orb) {
-			pci_free_consistent(hi->host->pdev,
-					sizeof(struct sbp2_reconnect_orb),
-					scsi_id->reconnect_orb,
-					scsi_id->reconnect_orb_dma);
-			SBP2_DMA_FREE("reconnect ORB DMA");
-		}
-
-		if (scsi_id->login_response) {
-			pci_free_consistent(hi->host->pdev,
-					sizeof(struct sbp2_login_response),
-					scsi_id->login_response,
-					scsi_id->login_response_dma);
-			SBP2_DMA_FREE("login FIFO DMA");
-		}
-
-		kfree(scsi_id);
-alloc_fail_first:
-		SBP2_ERR ("sbp2: Could not allocate memory for scsi_id");
-		return(-ENOMEM);
-	}
-	SBP2_DMA_ALLOC("consistent DMA region for login ORB");
-
-	/*
-	 * Initialize some of the fields in this structure
-	 */
-	scsi_id->node_id = node_id;
-	scsi_id->node_unique_id = node_unique_id;
-	scsi_id->validated = 1;
-	scsi_id->speed_code = SPEED_100;
-	scsi_id->max_payload_size = MAX_PAYLOAD_S100;
-
-	init_waitqueue_head(&scsi_id->sbp2_login_wait);
-
-	/* 
-	 * Initialize structures needed for the command orb pool.
-	 */
-	INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_inuse);
-	INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_completed);
-	scsi_id->sbp2_command_orb_lock = SPIN_LOCK_UNLOCKED;
-	scsi_id->sbp2_total_command_orbs = 0;
-
-	/*
-	 * Make sure that we've gotten ahold of the sbp2 management agent address. Also figure out the
-	 * command set being used (SCSI or RBC).
-	 */
-	if (sbp2_parse_unit_directory(hi, scsi_id)) {
-		SBP2_ERR("sbp2: Error while parsing sbp2 unit directory");
-		hi->scsi_id[i]->validated = 0;
-		return(-EIO);
-	}
-
-	scsi_id->sbp2_total_command_orbs = SBP2_MAX_COMMAND_ORBS;
-
-	/* 
-	 * Knock the total command orbs down if we are serializing I/O
-	 */
-	if (serialize_io) {
-		scsi_id->sbp2_total_command_orbs = 2;	/* one extra for good measure */
-	}
-
-	/*
-	 * Allocate some extra command orb structures for devices with 128KB limit
-	 */
-	if (scsi_id->sbp2_firmware_revision == SBP2_128KB_BROKEN_FIRMWARE) {
-		scsi_id->sbp2_total_command_orbs *= 4;
-	} 
-
-	/*
-	 * Create our command orb pool
-	 */
-	if (sbp2util_create_command_orb_pool(scsi_id, hi)) {
-		SBP2_ERR("sbp2: sbp2util_create_command_orb_pool failed!");
-		hi->scsi_id[i]->validated = 0;
-		return (-ENOMEM);
-	}
-
-	/*
-	 * Find an empty spot to stick our scsi id instance data. 
-	 */
-	for (i=0; i<SBP2SCSI_MAX_SCSI_IDS; i++) {
-		if (!hi->scsi_id[i]) {
-			hi->scsi_id[i] = scsi_id;
-			SBP2_DEBUG("sbp2: New SBP-2 device inserted, SCSI ID = %x", (unsigned int) i);
-			break;
-		}
-	}
-
-	/*
-	 * Make sure we are not out of space
-	 */
-	if (i >= SBP2SCSI_MAX_SCSI_IDS) {
-		SBP2_ERR("sbp2: No slots left for SBP-2 device");
-		hi->scsi_id[i]->validated = 0;
-		return(-EBUSY);
-	}
-
-	/*
-	 * Login to the sbp-2 device
-	 */
-	if (sbp2_login_device(hi, hi->scsi_id[i])) {
-
-		/*
-		 * Login failed... so, just mark him as unvalidated, so that he gets cleaned up later
-		 */
-		SBP2_ERR("sbp2: sbp2_login_device failed");
-		hi->scsi_id[i]->validated = 0;
-	}
-
-	if (hi->scsi_id[i]->validated) {
-
-		/*
-		 * Set max retries to something large on the device
-		 */
-		sbp2_set_busy_timeout(hi, hi->scsi_id[i]);
-
-		/*
-		 * Do a SBP-2 fetch agent reset
-		 */
-		sbp2_agent_reset(hi, hi->scsi_id[i], 0);
-
-		/*
-		 * Get the max speed and packet size that we can use
-		 */
-		sbp2_max_speed_and_size(hi, hi->scsi_id[i]);
-
-	}
-
-	return(0);
-}
-
-/*
- * This function tries to determine if a device is a valid SBP-2 device
- */
-static int sbp2_check_device(struct sbp2scsi_host_info *hi, int node_id)
-{
-	quadlet_t unit_spec_id_data = 0, unit_sw_ver_data = 0;
-	quadlet_t unit_directory_length, current_quadlet;
-	u64 unit_directory_addr, current_addr;
-	unsigned int i, length;
-
-	SBP2_DEBUG("sbp2: sbp2_check_device");
-
-	/*
-	 * Let's try and read the unit spec id and unit sw ver to determine if this is an SBP2 device...
-	 */
-
-	if (sbp2util_unit_directory(hi, LOCAL_BUS | node_id, &unit_directory_addr)) {
-		SBP2_DEBUG("sbp2: Error reading unit directory address - bad status");
-		return(-EIO);   
-	}
-
-	/*
-	 * Read the size of the unit directory
-	 */
-	if (sbp2util_read_quadlet(hi, LOCAL_BUS | node_id, unit_directory_addr, 
-				  &unit_directory_length)) {
-		SBP2_DEBUG("sbp2: Error reading root directory length - bad status");
-		return(-EIO);   
-	}
-
-	current_addr = unit_directory_addr;
-	length = be32_to_cpu(unit_directory_length) >> 16;
-
-	/*
-	 * Now, step through the unit directory and look for the unit_spec_ID and the unit_sw_version
-	 */
-	for (i=0; i < length; i++) {
-
-		current_addr += 4;
-
-		if (sbp2util_read_quadlet(hi, LOCAL_BUS | node_id, current_addr, &current_quadlet)) {
-			SBP2_DEBUG("sbp2: Error reading at address 0x%08x%08x - bad status", 
-				   (unsigned int) ((current_addr) >> 32), (unsigned int) ((current_addr) & 0xffffffff));
-			return(-EIO);   
-		}
-
-		/* 
-		 * Check for unit_spec_ID tag 
-		 */
-		if ((be32_to_cpu(current_quadlet) >> 24) == SBP2_UNIT_SPEC_ID_KEY) {
-			unit_spec_id_data = current_quadlet;
-			SBP2_DEBUG("sbp2: Node %x, unit spec id = %x", (LOCAL_BUS | node_id), 
-				   (unsigned int) be32_to_cpu(unit_spec_id_data));
-		}
-
-		/* 
-		 * Check for unit_sw_version tag 
-		 */
-		if ((be32_to_cpu(current_quadlet) >> 24) == SBP2_UNIT_SW_VERSION_KEY) {
-			unit_sw_ver_data = current_quadlet;
-			SBP2_DEBUG("sbp2: Node %x, unit sw version = %x", (LOCAL_BUS | node_id), 
-				   (unsigned int) be32_to_cpu(unit_sw_ver_data));
-		}
-	}
-
-	/*
-	 * Validate unit spec id and unit sw ver to see if this is an SBP-2 device
-	 */
-	if ((be32_to_cpu(unit_spec_id_data) != SBP2_UNIT_SPEC_ID_ENTRY) ||
-	    (be32_to_cpu(unit_sw_ver_data) != SBP2_SW_VERSION_ENTRY)) {
-
-		/*
-		 * Not an sbp2 device
-		 */
-		return(-ENXIO);
-	}
-
-	/*
-	 * This device is a valid SBP-2 device
-	 */
-	SBP2_INFO("sbp2: Node 0x%04x, Found SBP-2 device", (LOCAL_BUS | node_id));
-	return(0);
-}
-
-/*
- * This function removes (cleans-up after) any unvalidated sbp2 devices
- */
-static void sbp2_remove_unvalidated_devices(struct sbp2scsi_host_info *hi)
-{
-	int i;
-
-	/*
-	 * Loop through and free any unvalidated scsi id instance data structures
-	 */
-	for (i=0; i<SBP2SCSI_MAX_SCSI_IDS; i++) {
-		if (hi->scsi_id[i]) {
-			if (!hi->scsi_id[i]->validated) {
-
-				/*
-				 * Complete any pending commands with selection timeout
-				 */
-				sbp2scsi_complete_all_commands(hi, hi->scsi_id[i], DID_NO_CONNECT);
-       			
-				/* 
-				 * Clean up any other structures
-				 */
-				if (hi->scsi_id[i]->sbp2_total_command_orbs) {
-					sbp2util_remove_command_orb_pool(hi->scsi_id[i], hi);
-				}
-				if (hi->scsi_id[i]->login_response) {
-					pci_free_consistent(hi->host->pdev,
-							    sizeof(struct sbp2_login_response),
-							    hi->scsi_id[i]->login_response,
-							    hi->scsi_id[i]->login_response_dma);
-					SBP2_DMA_FREE("single login FIFO");
-				}
-
-				if (hi->scsi_id[i]->login_orb) {
-					pci_free_consistent(hi->host->pdev,
-							    sizeof(struct sbp2_login_orb),
-							    hi->scsi_id[i]->login_orb,
-							    hi->scsi_id[i]->login_orb_dma);
-					SBP2_DMA_FREE("single login ORB");
-				}
-
-				if (hi->scsi_id[i]->reconnect_orb) {
-					pci_free_consistent(hi->host->pdev,
-							    sizeof(struct sbp2_reconnect_orb),
-							    hi->scsi_id[i]->reconnect_orb,
-							    hi->scsi_id[i]->reconnect_orb_dma);
-					SBP2_DMA_FREE("single reconnect orb");
-				}
-
-				if (hi->scsi_id[i]->logout_orb) {
-					pci_free_consistent(hi->host->pdev,
-							    sizeof(struct sbp2_logout_orb),
-							    hi->scsi_id[i]->logout_orb,
-							    hi->scsi_id[i]->reconnect_orb_dma);
-					SBP2_DMA_FREE("single logout orb");
-				}
-
-				kfree(hi->scsi_id[i]);
-				hi->scsi_id[i] = NULL;
-				SBP2_DEBUG("sbp2: Unvalidated SBP-2 device removed, SCSI ID = %x", (unsigned int) i);
-			}
-		}
-	}
-
-	return;
-}
-
-/*
- * This function is our reset handler. It is run out of a thread, since we get 
- * notified of a bus reset from a bh (or interrupt).
- */
-static void sbp2_bus_reset_handler(void *context)
-{
-	struct sbp2scsi_host_info *hi = context;
-	quadlet_t signature_data;
-	int i;
-	unsigned long flags;
-	struct scsi_id_instance_data *scsi_id;
-
-	SBP2_DEBUG("sbp2: sbp2_bus_reset_handler");
-
-	/*
-	 * TODO. Check and keep track of generation number of all requests, in case a
-	 * bus reset occurs while trying to find and login to SBP-2 devices.
-	 */
-
-	/*
-	 * First thing to do. Invalidate all SBP-2 devices. This is needed so that
-	 * we stop sending down I/O requests to the device, and also so that we can
-	 * figure out which devices have disappeared after a bus reset.
-	 */
-	for (i=0; i<SBP2SCSI_MAX_SCSI_IDS; i++) {
-		if (hi->scsi_id[i]) {
-			hi->scsi_id[i]->validated = 0;
+		if (scsi_id->reconnect_orb) {
+			pci_free_consistent(hi->host->pdev,
+					sizeof(struct sbp2_reconnect_orb),
+					scsi_id->reconnect_orb,
+					scsi_id->reconnect_orb_dma);
+			SBP2_DMA_FREE("reconnect ORB DMA");
+		}
+
+		if (scsi_id->login_response) {
+			pci_free_consistent(hi->host->pdev,
+					sizeof(struct sbp2_login_response),
+					scsi_id->login_response,
+					scsi_id->login_response_dma);
+			SBP2_DMA_FREE("login FIFO DMA");
 		}
+
+		kfree(scsi_id);
+alloc_fail_first:
+		SBP2_ERR ("sbp2: Could not allocate memory for scsi_id");
+		return(-ENOMEM);
 	}
+	SBP2_DMA_ALLOC("consistent DMA region for login ORB");
 
 	/*
-	 * Give the sbp2 devices a little time to recover after the bus reset
+	 * Initialize some of the fields in this structure
 	 */
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(HZ/2);		/* 1/2 second delay */
+	scsi_id->ne = ne;
+	scsi_id->ud = ud;
+	scsi_id->speed_code = SPEED_100;
+	scsi_id->max_payload_size = MAX_PAYLOAD_S100;
+	ud->driver_data = scsi_id;
 
-	/*
-	 * Spit out what we know from the host
+	init_waitqueue_head(&scsi_id->sbp2_login_wait);
+
+	/* 
+	 * Initialize structures needed for the command orb pool.
 	 */
-	SBP2_DEBUG("host: node_count = %x", (unsigned int) hi->host->node_count);
-	SBP2_DEBUG("host: selfid_count = %x", (unsigned int) hi->host->selfid_count);
-	SBP2_DEBUG("host: node_id = %x", (unsigned int) hi->host->node_id);
-	SBP2_DEBUG("host: irm_id = %x", (unsigned int) hi->host->irm_id);
-	SBP2_DEBUG("host: busmgr_id = %x", (unsigned int) hi->host->busmgr_id);
-	SBP2_DEBUG("host: is_root = %x", (unsigned int) hi->host->is_root);
-	SBP2_DEBUG("host: is_cycmst = %x", (unsigned int) hi->host->is_cycmst);
-	SBP2_DEBUG("host: is_irm = %x", (unsigned int) hi->host->is_irm);
-	SBP2_DEBUG("host: is_busmgr = %x", (unsigned int) hi->host->is_busmgr);
+	INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_inuse);
+	INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_completed);
+	scsi_id->sbp2_command_orb_lock = SPIN_LOCK_UNLOCKED;
+	scsi_id->sbp2_total_command_orbs = 0;
 
 	/*
-	 * Let's try and figure out which devices out there are SBP-2 devices! Loop through all 
-	 * nodes out there.
+	 * Make sure that we've gotten ahold of the sbp2 management agent
+	 * address. Also figure out the command set being used (SCSI or
+	 * RBC).
 	 */
-	for (i=0; i<hi->host->node_count; i++) {
-
-		/*
-		 * Don't read from ourselves!
-		 */
-		if (i != ((hi->host->node_id) & NODE_MASK)) {
-
-			/*
-			 * Try and send a request for a config rom signature. This is expected to fail for
-			 * some nodes, as they might be repeater phys or not be initialized.
-			 */
-			if (!sbp2util_read_quadlet(hi, LOCAL_BUS | i, CONFIG_ROM_SIGNATURE_ADDRESS, &signature_data)) {
+	sbp2_parse_unit_directory(scsi_id);
 
-				if (be32_to_cpu(signature_data) == IEEE1394_CONFIG_ROM_SIGNATURE) {
-
-					/*
-					 * Hey, we've got a valid responding IEEE1394 node. Need to now see if it's an SBP-2 device
-					 */
-					if (!sbp2_check_device(hi, i)) {
+	scsi_id->sbp2_total_command_orbs = SBP2_MAX_COMMAND_ORBS;
 
-						/*
-						 * Found an SBP-2 device. Now, actually start the device.
-						 */
-						sbp2_start_device(hi, i);
-					}
-				}
-			}
-		}
+	/* 
+	 * Knock the total command orbs down if we are serializing I/O
+	 */
+	if (serialize_io) {
+		scsi_id->sbp2_total_command_orbs = 2;	/* one extra for good measure */
 	}
 
 	/*
-	 * This code needs protection
+	 * Allocate some extra command orb structures for devices with
+	 * 128KB limit.
 	 */
-	sbp2_spin_lock(&hi->sbp2_command_lock, flags);
+	if (scsi_id->sbp2_firmware_revision == SBP2_128KB_BROKEN_FIRMWARE) {
+		scsi_id->sbp2_total_command_orbs *= 4;
+	} 
 
 	/*
-	 * Ok, we've discovered and re-validated all SBP-2 devices out there. Let's remove structures of all
-	 * devices not re-validated (meaning they've been removed).
+	 * Find an empty spot to stick our scsi id instance data. 
 	 */
-	sbp2_remove_unvalidated_devices(hi);
+	for (i = 0; i < SBP2SCSI_MAX_SCSI_IDS; i++) {
+		if (!hi->scsi_id[i]) {
+			hi->scsi_id[i] = scsi_id;
+			scsi_id->id = i;
+			SBP2_DEBUG("sbp2: New SBP-2 device inserted, SCSI ID = %x", (unsigned int) i);
+			break;
+		}
+	}
 
 	/*
-	 * Complete any pending commands with busy (so they get retried) and remove them from our queue
+	 * Create our command orb pool
 	 */
-	for (i=0; i<SBP2SCSI_MAX_SCSI_IDS; i++) {
-		if (hi->scsi_id[i]) {
-			sbp2scsi_complete_all_commands(hi, hi->scsi_id[i], DID_BUS_BUSY);
-		}
+	if (sbp2util_create_command_orb_pool(scsi_id, hi)) {
+		SBP2_ERR("sbp2: sbp2util_create_command_orb_pool failed!");
+		sbp2_remove_device(hi, scsi_id);
+		return -ENOMEM;
 	}
 
 	/*
-	 * Now, note that the bus reset is complete (finally!)
+	 * Make sure we are not out of space
 	 */
-	hi->bus_reset_in_progress = 0;
+	if (i == SBP2SCSI_MAX_SCSI_IDS) {
+		SBP2_ERR("sbp2: No slots left for SBP-2 device");
+		sbp2_remove_device(hi, scsi_id);
+		return -EBUSY;
+	}
 
 	/*
-	 * Deal with the initial scsi bus scan if needed (since we only now know if there are
-	 * any sbp2 devices attached)
+	 * Login to the sbp-2 device
 	 */
-	if (!no_bus_scan && !hi->initial_scsi_bus_scan_complete && hi->bus_scan_SCpnt) {
+	if (sbp2_login_device(hi, scsi_id)) {
 
-		hi->initial_scsi_bus_scan_complete = 1;			
-		scsi_id = hi->scsi_id[hi->bus_scan_SCpnt->target];
-
-		/* 
-		 * If the sbp2 device exists, then let's now execute the command.
-		 * If not, then just complete it as a selection time-out. 
+		/*
+		 * Login failed... so, just mark him as unvalidated, so
+		 * that he gets cleaned up later.
 		 */
-                if (scsi_id) {
-			if (sbp2_send_command(hi, scsi_id, hi->bus_scan_SCpnt, hi->bus_scan_done)) {
-				SBP2_ERR("sbp2: Error sending SCSI command");
-				sbp2scsi_complete_command(hi, scsi_id, SBP2_SCSI_STATUS_SELECTION_TIMEOUT,
-							  hi->bus_scan_SCpnt, hi->bus_scan_done);
-			}
-		} else {
-			void (*done)(Scsi_Cmnd *) = hi->bus_scan_done;
-			hi->bus_scan_SCpnt->result = DID_NO_CONNECT << 16;
-			done (hi->bus_scan_SCpnt);
-		}
+		SBP2_ERR("sbp2: sbp2_login_device failed");
+		sbp2_remove_device(hi, scsi_id);
+		return -EBUSY;
 	}
 
-	sbp2_spin_unlock(&hi->sbp2_command_lock, flags);
+	/*
+	 * Set max retries to something large on the device
+	 */
+	sbp2_set_busy_timeout(hi, scsi_id);
+	
+	/*
+	 * Do a SBP-2 fetch agent reset
+	 */
+	sbp2_agent_reset(hi, scsi_id, 0);
+	
+	/*
+	 * Get the max speed and packet size that we can use
+	 */
+	sbp2_max_speed_and_size(hi, scsi_id);
 
-	return;
+	return 0;
 }
 
-
 /*
- * This is called from the host's bh when a bus reset is complete. We wake up our detection thread
- * to deal with the reset
+ * This function removes (cleans-up after) any unvalidated sbp2 devices
  */
-static void sbp2_host_reset(struct hpsb_host *host)
+static void sbp2_remove_device(struct sbp2scsi_host_info *hi, 
+			       struct scsi_id_instance_data *scsi_id)
 {
-	unsigned long flags;
-	struct sbp2scsi_host_info *hi;
-	int i;
-
-	SBP2_INFO("sbp2: IEEE-1394 bus reset");
-	sbp2_spin_lock(&sbp2_host_info_lock, flags);
-	hi = sbp2_find_host_info(host);
-
-	if (hi != NULL) {
-
-		/*
-		 * Wake up our detection thread, only if it's not already handling a reset
-		 */
-		if (!hi->bus_reset_in_progress) {
-
-			/*
-			 * First thing to do. Invalidate all SBP-2 devices. This is needed so that
-			 * we stop sending down I/O requests to the device, and also so that we can
-			 * figure out which devices have disappeared after a bus reset.
-			 */
-			for (i=0; i<SBP2SCSI_MAX_SCSI_IDS; i++) {
-				if (hi->scsi_id[i]) {
-					hi->scsi_id[i]->validated = 0;
-				}
-			}
+	/* Complete any pending commands with selection timeout */
+	sbp2scsi_complete_all_commands(hi, scsi_id, DID_NO_CONNECT);
+       			
+	/* Clean up any other structures */
+	if (scsi_id->sbp2_total_command_orbs) {
+		sbp2util_remove_command_orb_pool(scsi_id, hi);
+	}
 
-			hi->bus_reset_in_progress = 1;
+	if (scsi_id->login_response) {
+		pci_free_consistent(hi->host->pdev,
+				    sizeof(struct sbp2_login_response),
+				    scsi_id->login_response,
+				    scsi_id->login_response_dma);
+		SBP2_DMA_FREE("single login FIFO");
+	}
 
-			wake_up(&hi->sbp2_detection_wait);
-		}
+	if (scsi_id->login_orb) {
+		pci_free_consistent(hi->host->pdev,
+				    sizeof(struct sbp2_login_orb),
+				    scsi_id->login_orb,
+				    scsi_id->login_orb_dma);
+		SBP2_DMA_FREE("single login ORB");
 	}
-	sbp2_spin_unlock(&sbp2_host_info_lock, flags);
-	return;
-}
 
-/* XXX: How best to handle these with DMA interface? */
+	if (scsi_id->reconnect_orb) {
+		pci_free_consistent(hi->host->pdev,
+				    sizeof(struct sbp2_reconnect_orb),
+				    scsi_id->reconnect_orb,
+				    scsi_id->reconnect_orb_dma);
+		SBP2_DMA_FREE("single reconnect orb");
+	}
 
-#if 0
-/*
- * This function deals with physical dma write requests (for adapters that do not support
- * physical dma in hardware).
- */
-static int sbp2_handle_physdma_write(struct hpsb_host *host, int nodeid, quadlet_t *data,
-				     u64 addr, unsigned int length)
-{
+	if (scsi_id->logout_orb) {
+		pci_free_consistent(hi->host->pdev,
+				    sizeof(struct sbp2_logout_orb),
+				    scsi_id->logout_orb,
+				    scsi_id->reconnect_orb_dma);
+		SBP2_DMA_FREE("single logout orb");
+	}
 
-	/*
-	 * Manually put the data in the right place.
-	 */
-	memcpy(bus_to_virt((u32)addr), data, length);
-	return(RCODE_COMPLETE);
+	SBP2_DEBUG("sbp2: Unvalidated SBP-2 device removed, SCSI ID = %d", 
+		   scsi_id->id);
+	hi->scsi_id[scsi_id->id] = NULL;
+	kfree(scsi_id);
 }
 
-/*
- * This function deals with physical dma read requests (for adapters that do not support
- * physical dma in hardware).
- */
-static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid, quadlet_t *data,
-				    u64 addr, unsigned int length)
-{
-
-	/*
-	 * Grab data from memory and send a read response.
-	 */
-	memcpy(data, bus_to_virt((u32)addr), length);
-	return(RCODE_COMPLETE);
-}
-#endif
+
 
 /**************************************
  * SBP-2 protocol related section
  **************************************/
 
 /*
- * This function is called in order to login to a particular SBP-2 device, after a bus reset
+ * This function is called in order to login to a particular SBP-2 device,
+ * after a bus reset.
  */
 static int sbp2_login_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) 
 {
@@ -1808,34 +1298,28 @@
 		return(-EIO);
 	}
 
-	/*
-	 * Set-up login ORB
-	 */
-	scsi_id->login_orb->password_hi = 0;		/* Assume no password */
+	/* Set-up login ORB, assume no password */
+	scsi_id->login_orb->password_hi = 0; 
 	scsi_id->login_orb->password_lo = 0;
 	SBP2_DEBUG("sbp2: sbp2_login_device: password_hi/lo initialized");
-#ifdef SBP2_NEED_LOGIN_DESCRIPTOR_WORKAROUND
-	scsi_id->login_orb->login_response_lo = cpu_to_le32(scsi_id->login_response_dma);
-	scsi_id->login_orb->login_response_hi = cpu_to_le32(ORB_SET_NODE_ID(hi->host->node_id));
-#else
+
 	scsi_id->login_orb->login_response_lo = scsi_id->login_response_dma;
 	scsi_id->login_orb->login_response_hi = ORB_SET_NODE_ID(hi->host->node_id);
-#endif
 	SBP2_DEBUG("sbp2: sbp2_login_device: login_response_hi/lo initialized");
+
 	scsi_id->login_orb->lun_misc = ORB_SET_FUNCTION(LOGIN_REQUEST);
 	scsi_id->login_orb->lun_misc |= ORB_SET_RECONNECT(0);	/* One second reconnect time */
 	scsi_id->login_orb->lun_misc |= ORB_SET_EXCLUSIVE(1);	/* Exclusive access to device */
 	scsi_id->login_orb->lun_misc |= ORB_SET_NOTIFY(1);		/* Notify us of login complete */
 	SBP2_DEBUG("sbp2: sbp2_login_device: lun_misc initialized");
-	scsi_id->login_orb->passwd_resp_lengths = ORB_SET_LOGIN_RESP_LENGTH(sizeof(struct sbp2_login_response));
+
+	scsi_id->login_orb->passwd_resp_lengths =
+		ORB_SET_LOGIN_RESP_LENGTH(sizeof(struct sbp2_login_response));
 	SBP2_DEBUG("sbp2: sbp2_login_device: passwd_resp_lengths initialized");
-#ifdef SBP2_NEED_LOGIN_DESCRIPTOR_WORKAROUND
-	scsi_id->login_orb->status_FIFO_lo = cpu_to_le32((u32)SBP2_STATUS_FIFO_ADDRESS_LO);
-	scsi_id->login_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) | cpu_to_le16(SBP2_STATUS_FIFO_ADDRESS_HI));
-#else
+
 	scsi_id->login_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO;
-	scsi_id->login_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) | SBP2_STATUS_FIFO_ADDRESS_HI);
-#endif
+	scsi_id->login_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) |
+					      SBP2_STATUS_FIFO_ADDRESS_HI);
 	SBP2_DEBUG("sbp2: sbp2_login_device: status FIFO initialized");
 
 	/*
@@ -1861,25 +1345,26 @@
 	sbp2util_cpu_to_be32_buffer(data, 8);
 
 	SBP2_DEBUG("sbp2: sbp2_login_device: prepared to write");
-
-	hpsb_write(hi->host, LOCAL_BUS | scsi_id->node_id, scsi_id->sbp2_management_agent_addr, data, 8);
+	hpsb_write(hi->host, LOCAL_BUS | scsi_id->ne->nodeid, scsi_id->sbp2_management_agent_addr, data, 8);
+	SBP2_DEBUG("sbp2: sbp2_login_device: written");
 
 	/*
-	 * Wait for login status... but, only if the device has not already logged-in (some devices are fast)
+	 * Wait for login status... but, only if the device has not
+	 * already logged-in (some devices are fast)
 	 */
 
-	SBP2_DEBUG("sbp2: sbp2_login_device: written");
 	save_flags(flags);
 	cli();
-	if (scsi_id->status_block.ORB_offset_lo != scsi_id->login_orb_dma) {
-		interruptible_sleep_on_timeout(&scsi_id->sbp2_login_wait, 10*HZ);		/* 10 second timeout */
-	}
+	/* 10 second timeout */
+	if (scsi_id->status_block.ORB_offset_lo != scsi_id->login_orb_dma)
+		sleep_on_timeout(&scsi_id->sbp2_login_wait, 10*HZ);
 	restore_flags(flags);
 
 	SBP2_DEBUG("sbp2: sbp2_login_device: initial check");
 
 	/*
-	 * Match status to the login orb. If they do not match, it's probably because the login timed-out
+	 * Match status to the login orb. If they do not match, it's
+	 * probably because the login timed-out.
 	 */
 	if (scsi_id->status_block.ORB_offset_lo != scsi_id->login_orb_dma) {
 		SBP2_ERR("sbp2: Error logging into SBP-2 device - login timed-out");
@@ -1900,17 +1385,21 @@
 	}
 
 	/*
-	 * Byte swap the login response, for use when reconnecting or logging out.
+	 * Byte swap the login response, for use when reconnecting or
+	 * logging out.
 	 */
 	sbp2util_cpu_to_be32_buffer(scsi_id->login_response, sizeof(struct sbp2_login_response));
 
 	/*
-	 * Grab our command block agent address from the login response
+	 * Grab our command block agent address from the login response.
 	 */
-	SBP2_DEBUG("sbp2: command_block_agent_hi = %x", (unsigned int)scsi_id->login_response->command_block_agent_hi);
-	SBP2_DEBUG("sbp2: command_block_agent_lo = %x", (unsigned int)scsi_id->login_response->command_block_agent_lo);
+	SBP2_DEBUG("sbp2: command_block_agent_hi = %x",
+		   (unsigned int)scsi_id->login_response->command_block_agent_hi);
+	SBP2_DEBUG("sbp2: command_block_agent_lo = %x",
+		   (unsigned int)scsi_id->login_response->command_block_agent_lo);
 
-	scsi_id->sbp2_command_block_agent_addr = ((u64)scsi_id->login_response->command_block_agent_hi) << 32;
+	scsi_id->sbp2_command_block_agent_addr =
+		((u64)scsi_id->login_response->command_block_agent_hi) << 32;
 	scsi_id->sbp2_command_block_agent_addr |= ((u64)scsi_id->login_response->command_block_agent_lo);
 	scsi_id->sbp2_command_block_agent_addr &= 0x0000ffffffffffffULL;
 
@@ -1921,8 +1410,8 @@
 }
 
 /*
- * This function is called in order to logout from a particular SBP-2 device, usually called during driver
- * unload
+ * This function is called in order to logout from a particular SBP-2
+ * device, usually called during driver unload.
  */
 static int sbp2_logout_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) 
 {
@@ -1937,17 +1426,17 @@
 	scsi_id->logout_orb->reserved2 = 0x0;
 	scsi_id->logout_orb->reserved3 = 0x0;
 	scsi_id->logout_orb->reserved4 = 0x0;
+
 	scsi_id->logout_orb->login_ID_misc = ORB_SET_FUNCTION(LOGOUT_REQUEST);
 	scsi_id->logout_orb->login_ID_misc |= ORB_SET_LOGIN_ID(scsi_id->login_response->length_login_ID);
-	scsi_id->logout_orb->login_ID_misc |= ORB_SET_NOTIFY(1);		/* Notify us when complete */
+
+	/* Notify us when complete */
+	scsi_id->logout_orb->login_ID_misc |= ORB_SET_NOTIFY(1);
+
 	scsi_id->logout_orb->reserved5 = 0x0;
-#ifdef SBP2_NEED_LOGIN_DESCRIPTOR_WORKAROUND
-	scsi_id->logout_orb->status_FIFO_lo = cpu_to_le32((u32)SBP2_STATUS_FIFO_ADDRESS_LO);
-	scsi_id->logout_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) | cpu_to_le16(SBP2_STATUS_FIFO_ADDRESS_HI));
-#else
 	scsi_id->logout_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO;
-	scsi_id->logout_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) | SBP2_STATUS_FIFO_ADDRESS_HI);
-#endif
+	scsi_id->logout_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) |
+					       SBP2_STATUS_FIFO_ADDRESS_HI);
 
 	/*
 	 * Byte swap ORB if necessary
@@ -1961,12 +1450,10 @@
 	data[1] = scsi_id->logout_orb_dma;
 	sbp2util_cpu_to_be32_buffer(data, 8);
 
-	hpsb_write(hi->host, LOCAL_BUS | scsi_id->node_id, scsi_id->sbp2_management_agent_addr, data, 8);
+	hpsb_write(hi->host, LOCAL_BUS | scsi_id->ne->nodeid, scsi_id->sbp2_management_agent_addr, data, 8);
 
-	/*
-	 * Wait for device to logout... 
-	 */
-	interruptible_sleep_on_timeout(&scsi_id->sbp2_login_wait, HZ);		/* 1 second timeout */
+	/* Wait for device to logout...1 second. */
+	sleep_on_timeout(&scsi_id->sbp2_login_wait, HZ);
 
 	SBP2_INFO("sbp2: Logged out of SBP-2 device");
 
@@ -1975,7 +1462,8 @@
 }
 
 /*
- * This function is called in order to reconnect to a particular SBP-2 device, after a bus reset
+ * This function is called in order to reconnect to a particular SBP-2
+ * device, after a bus reset.
  */
 static int sbp2_reconnect_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) 
 {
@@ -1991,18 +1479,19 @@
 	scsi_id->reconnect_orb->reserved2 = 0x0;
 	scsi_id->reconnect_orb->reserved3 = 0x0;
 	scsi_id->reconnect_orb->reserved4 = 0x0;
+
 	scsi_id->reconnect_orb->login_ID_misc = ORB_SET_FUNCTION(RECONNECT_REQUEST);
-	scsi_id->reconnect_orb->login_ID_misc |= ORB_SET_LOGIN_ID(scsi_id->login_response->length_login_ID);
-	scsi_id->reconnect_orb->login_ID_misc |= ORB_SET_NOTIFY(1);		/* Notify us when complete */
+	scsi_id->reconnect_orb->login_ID_misc |=
+		ORB_SET_LOGIN_ID(scsi_id->login_response->length_login_ID);
+
+	/* Notify us when complete */
+	scsi_id->reconnect_orb->login_ID_misc |= ORB_SET_NOTIFY(1);
+
 	scsi_id->reconnect_orb->reserved5 = 0x0;
-#ifdef SBP2_NEED_LOGIN_DESCRIPTOR_WORKAROUND
-	scsi_id->reconnect_orb->status_FIFO_lo = cpu_to_le32((u32)SBP2_STATUS_FIFO_ADDRESS_LO);
-	scsi_id->reconnect_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) | cpu_to_le16(SBP2_STATUS_FIFO_ADDRESS_HI));
-#else
 	scsi_id->reconnect_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO;
-	scsi_id->reconnect_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) | SBP2_STATUS_FIFO_ADDRESS_HI);
-#endif
-	
+	scsi_id->reconnect_orb->status_FIFO_hi =
+		(ORB_SET_NODE_ID(hi->host->node_id) | SBP2_STATUS_FIFO_ADDRESS_HI);
+
 	/*
 	 * Byte swap ORB if necessary
 	 */
@@ -2020,20 +1509,22 @@
 	data[1] = scsi_id->reconnect_orb_dma;
 	sbp2util_cpu_to_be32_buffer(data, 8);
 
-	hpsb_write(hi->host, LOCAL_BUS | scsi_id->node_id, scsi_id->sbp2_management_agent_addr, data, 8);
+	hpsb_write(hi->host, LOCAL_BUS | scsi_id->ne->nodeid, scsi_id->sbp2_management_agent_addr, data, 8);
 
 	/*
-	 * Wait for reconnect status... but, only if the device has not already reconnected (some devices are fast)
+	 * Wait for reconnect status... but, only if the device has not
+	 * already reconnected (some devices are fast).
 	 */
 	save_flags(flags);
 	cli();
-	if (scsi_id->status_block.ORB_offset_lo != scsi_id->reconnect_orb_dma) {
-		interruptible_sleep_on_timeout(&scsi_id->sbp2_login_wait, HZ);		/* one second timeout */
-	}
+	/* One second timout */
+	if (scsi_id->status_block.ORB_offset_lo != scsi_id->reconnect_orb_dma)
+		sleep_on_timeout(&scsi_id->sbp2_login_wait, HZ);
 	restore_flags(flags);
 
 	/*
-	 * Match status to the reconnect orb. If they do not match, it's probably because the reconnect timed-out
+	 * Match status to the reconnect orb. If they do not match, it's
+	 * probably because the reconnect timed-out.
 	 */
 	if (scsi_id->status_block.ORB_offset_lo != scsi_id->reconnect_orb_dma) {
 		SBP2_ERR("sbp2: Error reconnecting to SBP-2 device - reconnect timed-out");
@@ -2058,7 +1549,8 @@
 }
 
 /*
- * This function is called in order to set the busy timeout (number of retries to attempt) on the sbp2 device. 
+ * This function is called in order to set the busy timeout (number of
+ * retries to attempt) on the sbp2 device. 
  */
 static int sbp2_set_busy_timeout(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id)
 {      
@@ -2071,7 +1563,7 @@
 	 */
 	data = cpu_to_be32(SBP2_BUSY_TIMEOUT_VALUE);
 
-	if (hpsb_write(hi->host, LOCAL_BUS | scsi_id->node_id, SBP2_BUSY_TIMEOUT_ADDRESS, &data, 4)) {
+	if (hpsb_write(hi->host, LOCAL_BUS | scsi_id->ne->nodeid, SBP2_BUSY_TIMEOUT_ADDRESS, &data, 4)) {
 		SBP2_ERR("sbp2: sbp2_set_busy_timeout error");
 	}
 
@@ -2079,158 +1571,100 @@
 }
 
 /*
- * This function is called to parse sbp2 device's config rom unit directory. Used to determine
- * things like sbp2 management agent offset, and command set used (SCSI or RBC). 
+ * This function is called to parse sbp2 device's config rom unit
+ * directory. Used to determine things like sbp2 management agent offset,
+ * and command set used (SCSI or RBC). 
  */
-static int sbp2_parse_unit_directory(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id)
+static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id)
 {
-	quadlet_t unit_directory_length, unit_directory_data;
-	u64 unit_directory_addr;
-	u32 i;
+	struct unit_directory *ud;
+	int i;
 
 	SBP2_DEBUG("sbp2: sbp2_parse_unit_directory");
 
-	if (sbp2util_unit_directory(hi, LOCAL_BUS | scsi_id->node_id, &unit_directory_addr)) {
-		SBP2_DEBUG("sbp2: Error reading unit directory address - bad status");
-		return(-EIO);   
-	}
-
-	/*
-	 * Read the size of the unit directory
-	 */
-	if (sbp2util_read_quadlet(hi, LOCAL_BUS | scsi_id->node_id, unit_directory_addr, 
-				  &unit_directory_length)) {
-		SBP2_DEBUG("sbp2: Error reading unit directory length - bad status");
-		return(-EIO);   
-	}
-
-	unit_directory_length = ((be32_to_cpu(unit_directory_length)) >> 16);
-
-	/*
-	 * Now, sweep through the unit directory looking for the management agent offset
-	 * Give up if we hit any error or somehow miss it...
-	 */
-	for (i=0; i<unit_directory_length; i++) {
-
-		if (sbp2util_read_quadlet(hi, LOCAL_BUS | scsi_id->node_id, unit_directory_addr + (i<<2) + 4, 
-					  &unit_directory_data)) {
-			SBP2_DEBUG("sbp2: Error reading unit directory - bad status");
-			return(-EIO);
-		}
-
-		/* 
-		 * Handle different fields in the unit directory, based on keys
-		 */
-		unit_directory_data = be32_to_cpu(unit_directory_data);
-		switch (unit_directory_data >> 24) {
-			
-			case SBP2_CSR_OFFSET_KEY:
-
-				/*
-				 * Save off the management agent address
-				 */
-				scsi_id->sbp2_management_agent_addr = CONFIG_ROM_INITIAL_MEMORY_SPACE + 
-								      ((unit_directory_data & 0x00ffffff) << 2);
-
-				SBP2_DEBUG("sbp2: sbp2_management_agent_addr = %x", (unsigned int) scsi_id->sbp2_management_agent_addr);
-				break;
-
-			case SBP2_COMMAND_SET_SPEC_ID_KEY:
-
-				/*
-				 * Command spec organization
-				 */
-				scsi_id->sbp2_command_set_spec_id = unit_directory_data & 0xffffff;
-				SBP2_DEBUG("sbp2: sbp2_command_set_spec_id = %x", (unsigned int) scsi_id->sbp2_command_set_spec_id);
-				break;
-
-			case SBP2_COMMAND_SET_KEY:
-
-				/*
-				 * Command set used by sbp2 device
-				 */
-				scsi_id->sbp2_command_set = unit_directory_data & 0xffffff;
-				SBP2_DEBUG("sbp2: sbp2_command_set = %x", (unsigned int) scsi_id->sbp2_command_set);
-				break;
-
-			case SBP2_UNIT_CHARACTERISTICS_KEY:
-
-				/*
-				 * Unit characterisitcs (orb related stuff that I'm not yet paying attention to)
-				 */
-				scsi_id->sbp2_unit_characteristics = unit_directory_data & 0xffffff;
-				SBP2_DEBUG("sbp2: sbp2_unit_characteristics = %x", (unsigned int) scsi_id->sbp2_unit_characteristics);
-				break;
+	ud = scsi_id->ud;
 
-			case SBP2_DEVICE_TYPE_AND_LUN_KEY:
+	/* Handle different fields in the unit directory, based on keys */
+	for (i = 0; i < ud->arb_count; i++) {
+		switch (ud->arb_keys[i]) {
+		case SBP2_CSR_OFFSET_KEY:
+			/* Save off the management agent address */
+			scsi_id->sbp2_management_agent_addr =
+				CONFIG_ROM_INITIAL_MEMORY_SPACE + 
+				(ud->arb_values[i] << 2);
 
-				/*
-				 * Device type and lun (used for detemining type of sbp2 device)
-				 */
-				scsi_id->sbp2_device_type_and_lun = unit_directory_data & 0xffffff;
-				SBP2_DEBUG("sbp2: sbp2_device_type_and_lun = %x", (unsigned int) scsi_id->sbp2_device_type_and_lun);
-				break;
-
-			case SBP2_UNIT_SPEC_ID_KEY:
+			SBP2_DEBUG("sbp2: sbp2_management_agent_addr = %x",
+				   (unsigned int) scsi_id->sbp2_management_agent_addr);
+			break;
 
-				/*
-				 * Unit spec id (used for protocol detection)
-				 */
-				scsi_id->sbp2_unit_spec_id = unit_directory_data & 0xffffff;
-				SBP2_DEBUG("sbp2: sbp2_unit_spec_id = %x", (unsigned int) scsi_id->sbp2_unit_spec_id);
-				break;
+		case SBP2_COMMAND_SET_SPEC_ID_KEY:
+			/* Command spec organization */
+			scsi_id->sbp2_command_set_spec_id = ud->arb_values[i];
+			SBP2_DEBUG("sbp2: sbp2_command_set_spec_id = %x",
+				   (unsigned int) scsi_id->sbp2_command_set_spec_id);
+			break;
 
-			case SBP2_UNIT_SW_VERSION_KEY:
+		case SBP2_COMMAND_SET_KEY:
+			/* Command set used by sbp2 device */
+			scsi_id->sbp2_command_set = ud->arb_values[i];
+			SBP2_DEBUG("sbp2: sbp2_command_set = %x",
+				   (unsigned int) scsi_id->sbp2_command_set);
+			break;
 
-				/*
-				 * Unit sw version (used for protocol detection) 
-				 */
-				scsi_id->sbp2_unit_sw_version = unit_directory_data & 0xffffff;
-				SBP2_DEBUG("sbp2: sbp2_unit_sw_version = %x", (unsigned int) scsi_id->sbp2_unit_sw_version);
-				break;
+		case SBP2_UNIT_CHARACTERISTICS_KEY:
+			/*
+			 * Unit characterisitcs (orb related stuff
+			 * that I'm not yet paying attention to)
+			 */
+			scsi_id->sbp2_unit_characteristics = ud->arb_values[i];
+			SBP2_DEBUG("sbp2: sbp2_unit_characteristics = %x",
+				   (unsigned int) scsi_id->sbp2_unit_characteristics);
+			break;
 
-			case SBP2_FIRMWARE_REVISION_KEY:
+		case SBP2_DEVICE_TYPE_AND_LUN_KEY:
+			/*
+			 * Device type and lun (used for
+			 * detemining type of sbp2 device)
+			 */
+			scsi_id->sbp2_device_type_and_lun = ud->arb_values[i];
+			SBP2_DEBUG("sbp2: sbp2_device_type_and_lun = %x",
+				   (unsigned int) scsi_id->sbp2_device_type_and_lun);
+			break;
 
-				/*
-				 * Firmware revision (used to find broken devices). If the vendor id is 0xa0b8 
-				 * (Symbios vendor id), then we have a bridge with 128KB max transfer size limitation.
-				 */
-				scsi_id->sbp2_firmware_revision = unit_directory_data & 0xffff00;
-				if (scsi_id->sbp2_firmware_revision == SBP2_128KB_BROKEN_FIRMWARE) {
-					SBP2_WARN("sbp2: warning: Bridge chipset supports 128KB max transfer size");
-				}
-				break;
+		case SBP2_FIRMWARE_REVISION_KEY:
+			/*
+			 * Firmware revision (used to find broken
+			 * devices). If the vendor id is 0xa0b8
+			 * (Symbios vendor id), then we have a
+			 * bridge with 128KB max transfer size
+			 * limitation.
+			 */
+			scsi_id->sbp2_firmware_revision = ud->arb_values[i];
+			if (scsi_id->sbp2_firmware_revision ==
+			    SBP2_128KB_BROKEN_FIRMWARE) {
+				SBP2_WARN("sbp2: warning: Bridge chipset supports 128KB max transfer size");
+			}
+			break;
 
-			default:
-				break;
+		default:
+			break;
 		}
-
 	}
-
-	return(0);
 }
 
 /*
- * This function is called in order to determine the max speed and packet size we can use in our ORBs. 
+ * This function is called in order to determine the max speed and packet
+ * size we can use in our ORBs. 
  */
 static int sbp2_max_speed_and_size(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id)
 {
 	u8 speed_code;
-	struct node_entry *ne;
+	unsigned int max_rec;
 
 	SBP2_DEBUG("sbp2: sbp2_max_speed_and_size");
 
-	/* Get this nodes information */
-	ne = hpsb_nodeid_get_entry(hi->host->node_id);
-
-	if (!ne) {
-		HPSB_ERR("sbp2: Unknown device, using S100, payload 512 bytes");
-		scsi_id->speed_code = SPEED_100;
-		scsi_id->max_payload_size = MAX_PAYLOAD_S100;
-		return(0);
-	}
-
-	speed_code = ne->busopt.lnkspd;
+	speed_code = scsi_id->ne->busopt.lnkspd;
+	max_rec = scsi_id->ne->busopt.max_rec;
 
 	/* Bump down our speed if there is a module parameter forcing us slower */
 	if (speed_code > max_speed) {
@@ -2240,11 +1674,11 @@
 
 	/* Support the devices max_rec and max speed. We choose a setting
 	 * that fits both values, since they may differ.  */
-	if (speed_code >= SPEED_400 && ne->busopt.max_rec >= MAX_REC_S400) {
+	if (speed_code >= SPEED_400 && max_rec >= MAX_REC_S400) {
 		HPSB_INFO("sbp2: SBP-2 device max speed S400 and payload 2KB");
 		scsi_id->speed_code = SPEED_400;
 		scsi_id->max_payload_size = MAX_PAYLOAD_S400;
-	} else if (speed_code >= SPEED_200 && ne->busopt.max_rec >= MAX_REC_S200) {
+	} else if (speed_code >= SPEED_200 && max_rec >= MAX_REC_S200) {
 		HPSB_INFO("sbp2: SBP-2 device max speed S200 and payload 1KB");
 		scsi_id->speed_code = SPEED_200;
 		scsi_id->max_payload_size = MAX_PAYLOAD_S200;
@@ -2269,9 +1703,11 @@
 	/*
 	 * Ok, let's write to the target's management agent register
 	 */
-	agent_reset_request_packet = sbp2util_allocate_write_request_packet(hi, LOCAL_BUS | scsi_id->node_id,
-									    scsi_id->sbp2_command_block_agent_addr + SBP2_AGENT_RESET_OFFSET,
-									    0, ntohl(SBP2_AGENT_RESET_DATA));
+	agent_reset_request_packet =
+		sbp2util_allocate_write_request_packet(hi, LOCAL_BUS | scsi_id->ne->nodeid,
+						       scsi_id->sbp2_command_block_agent_addr +
+						       SBP2_AGENT_RESET_OFFSET,
+						       0, ntohl(SBP2_AGENT_RESET_DATA));
 
 	if (!agent_reset_request_packet) {
 		SBP2_ERR("sbp2: sbp2util_allocate_write_request_packet failed");
@@ -2299,8 +1735,8 @@
 }
 
 /*
- * This function is called to create the actual command orb and s/g list out of the 
- * scsi command itself. 
+ * This function is called to create the actual command orb and s/g list
+ * out of the scsi command itself.
  */
 static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi, 
 				   struct scsi_id_instance_data *scsi_id,
@@ -2321,9 +1757,10 @@
 	/*
 	 * Set-up our command ORB..
 	 *
-	 * NOTE: We're doing unrestricted page tables (s/g), as this is best performance 
-	 * (at least with the devices I have). This means that data_size becomes the number 
-	 * of s/g elements, and page_size should be zero (for unrestricted).
+	 * NOTE: We're doing unrestricted page tables (s/g), as this is
+	 * best performance (at least with the devices I have). This means
+	 * that data_size becomes the number of s/g elements, and
+	 * page_size should be zero (for unrestricted).
 	 */
 	command_orb->next_ORB_hi = 0xffffffff;
 	command_orb->next_ORB_lo = 0xffffffff;
@@ -2332,8 +1769,8 @@
 	command_orb->misc |= ORB_SET_NOTIFY(1);		/* Notify us when complete */
 
 	/*
-	 * Set-up our pagetable stuff... unfortunately, this has become messier than I'd like. Need to 
-	 * clean this up a bit.   ;-)
+	 * Set-up our pagetable stuff... unfortunately, this has become
+	 * messier than I'd like. Need to clean this up a bit.   ;-)
 	 */
 	if (sbp2scsi_direction_table[*scsi_cmd] == ORB_DIRECTION_NO_DATA_TRANSFER) {
 
@@ -2405,13 +1842,15 @@
 				}
 			}
 
-			command_orb->misc |= ORB_SET_DATA_SIZE(sg_count); /* number of page table (s/g) elements */
+			/* Number of page table (s/g) elements */
+			command_orb->misc |= ORB_SET_DATA_SIZE(sg_count);
 
 			/*
 			 * Byte swap page tables if necessary
 			 */
 			sbp2util_cpu_to_be32_buffer(scatter_gather_element, 
-						    (sizeof(struct sbp2_unrestricted_page_table)) * sg_count);
+						    (sizeof(struct sbp2_unrestricted_page_table)) *
+						    sg_count);
 
 		}
 
@@ -2427,8 +1866,8 @@
 		SBP2_DMA_ALLOC("single bulk");
 
 		/*
-		 * Handle case where we get a command w/o s/g enabled (but check
-		 * for transfers larger than 64K)
+		 * Handle case where we get a command w/o s/g enabled (but
+		 * check for transfers larger than 64K)
 		 */
 		if (scsi_request_bufflen <= SBP2_MAX_SG_ELEMENT_LENGTH) {
 
@@ -2438,7 +1877,8 @@
 			command_orb->misc |= ORB_SET_DIRECTION(sbp2scsi_direction_table[*scsi_cmd]);
 
 			/*
-			 * Sanity, in case our direction table is not up-to-date
+			 * Sanity, in case our direction table is not
+			 * up-to-date
 			 */
 			if (!scsi_request_bufflen) {
 				command_orb->data_descriptor_hi = 0xffffffff;
@@ -2448,15 +1888,19 @@
 
 		} else {
 			/*
-			 * Need to turn this into page tables, since the buffer is too large.
+			 * Need to turn this into page tables, since the
+			 * buffer is too large.
 			 */                     
 			command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
 			command_orb->data_descriptor_lo = command->sge_dma;
-			command_orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1);	/* use page tables (s/g) */
+
+			/* Use page tables (s/g) */
+			command_orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1);
 			command_orb->misc |= ORB_SET_DIRECTION(sbp2scsi_direction_table[*scsi_cmd]);
 
 			/*
-			 * fill out our sbp-2 page tables (and split up the large buffer)
+			 * fill out our sbp-2 page tables (and split up
+			 * the large buffer)
 			 */
 			sg_count = 0;
 			sg_len = scsi_request_bufflen;
@@ -2476,7 +1920,8 @@
 				sg_count++;
 			}
 
-			command_orb->misc |= ORB_SET_DATA_SIZE(sg_count); /* number of page table (s/g) elements */
+			/* Number of page table (s/g) elements */
+			command_orb->misc |= ORB_SET_DATA_SIZE(sg_count);
 
 			/*
 			 * Byte swap page tables if necessary
@@ -2524,11 +1969,12 @@
 		/*
 		 * Ok, let's write to the target's management agent register
 		 */
-		if (!hi->bus_reset_in_progress) {
+		if (hpsb_node_entry_valid(scsi_id->ne)) {
 
-			command_request_packet = sbp2util_allocate_write_request_packet(hi, LOCAL_BUS | scsi_id->node_id,
-											scsi_id->sbp2_command_block_agent_addr + SBP2_ORB_POINTER_OFFSET,
-											8, 0);
+			command_request_packet =
+				sbp2util_allocate_write_request_packet(hi, LOCAL_BUS | scsi_id->ne->nodeid,
+								scsi_id->sbp2_command_block_agent_addr +
+								SBP2_ORB_POINTER_OFFSET, 8, 0);
 		
 			if (!command_request_packet) {
 				SBP2_ERR("sbp2: sbp2util_allocate_write_request_packet failed");
@@ -2561,16 +2007,19 @@
 		 * modifying these next orb pointers, as they are accessed
 		 * both by the sbp2 device and us.
 		 */
-		scsi_id->last_orb->next_ORB_lo = cpu_to_be32(command->command_orb_dma);
-		scsi_id->last_orb->next_ORB_hi = 0x0;	/* Tells hardware that this pointer is valid */
-		
+		scsi_id->last_orb->next_ORB_lo =
+			cpu_to_be32(command->command_orb_dma);
+		/* Tells hardware that this pointer is valid */
+		scsi_id->last_orb->next_ORB_hi = 0x0;
+
 		/*
-		 * Only ring the doorbell if we need to (first parts of linked orbs don't need this)
+		 * Only ring the doorbell if we need to (first parts of
+		 * linked orbs don't need this).
 		 */
-		if (!command->linked && !hi->bus_reset_in_progress) {
+		if (!command->linked && hpsb_node_entry_valid(scsi_id->ne)) {
 
 			command_request_packet = sbp2util_allocate_write_request_packet(hi,
-				LOCAL_BUS | scsi_id->node_id,
+				LOCAL_BUS | scsi_id->ne->nodeid,
 				scsi_id->sbp2_command_block_agent_addr + SBP2_DOORBELL_OFFSET,
 				0, cpu_to_be32(command->command_orb_dma));
 	
@@ -2610,8 +2059,8 @@
 	SBP2_DEBUG("sbp2: SCSI s/g elements = %x", (unsigned int)SCpnt->use_sg);
 
 	/*
-	 * Check for broken devices that can't handle greater than 128K transfers, and deal with them in a 
-	 * hacked ugly way.
+	 * Check for broken devices that can't handle greater than 128K
+	 * transfers, and deal with them in a hacked ugly way.
 	 */
 	if ((scsi_id->sbp2_firmware_revision == SBP2_128KB_BROKEN_FIRMWARE) && 
 	    (SCpnt->request_bufflen > SBP2_BROKEN_FIRMWARE_MAX_TRANSFER) && 
@@ -2620,7 +2069,8 @@
 	    (*cmd == 0x28 || *cmd == 0x2a || *cmd == 0x0a || *cmd == 0x08)) {
 
 		/*
-		 * Darn, a broken device. We'll need to split up the transfer ourselves
+		 * Darn, a broken device. We'll need to split up the
+		 * transfer ourselves.
 		 */
 		sbp2_send_split_command(hi, scsi_id, SCpnt, done);
 		return(0);
@@ -2637,13 +2087,12 @@
 	/*
 	 * Now actually fill in the comamnd orb and sbp2 s/g list
 	 */
-	sbp2_create_command_orb(hi, scsi_id, command, cmd, SCpnt->use_sg, 
-				SCpnt->request_bufflen, SCpnt->request_buffer,
-				scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
-	
+	sbp2_create_command_orb(hi, scsi_id, command, cmd, SCpnt->use_sg,
+			SCpnt->request_bufflen, SCpnt->request_buffer,
+			scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); 
 	/*
-	 * Update our cdb if necessary (to handle sbp2 RBC command set differences).
-	 * This is where the command set hacks go!   =)
+	 * Update our cdb if necessary (to handle sbp2 RBC command set
+	 * differences).  This is where the command set hacks go!   =)
 	 */
 	if ((device_type == TYPE_DISK) ||
 	    (device_type == TYPE_SDAD) ||
@@ -2665,7 +2114,8 @@
 }
 
 /*
- * This function is called for broken sbp2 device, where we have to break up large transfers. 
+ * This function is called for broken sbp2 device, where we have to break
+ * up large transfers.
  */
 static int sbp2_send_split_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id,
 				   Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
@@ -2779,8 +2229,8 @@
 }
 
 /*
- * This function deals with command set differences between Linux scsi command set and sbp2 RBC
- * command set.
+ * This function deals with command set differences between Linux scsi
+ * command set and sbp2 RBC command set.
  */
 static void sbp2_check_sbp2_command(unchar *cmd)
 {
@@ -3001,9 +2451,9 @@
 	 */
 	for (i=0; i<SBP2SCSI_MAX_SCSI_IDS; i++) {
 		if (hi->scsi_id[i]) {
-			if (hi->scsi_id[i]->node_id == (nodeid & NODE_MASK)) {
+			if ((hi->scsi_id[i]->ne->nodeid & NODE_MASK) == (nodeid & NODE_MASK)) {
 				scsi_id = hi->scsi_id[i];
-				SBP2_DEBUG("sbp2: SBP-2 status write from node %x", scsi_id->node_id);
+				SBP2_DEBUG("sbp2: SBP-2 status write from node %x", scsi_id->ne->nodeid);
 				break;
 			}
 		}
@@ -3089,6 +2539,7 @@
 	return(RCODE_COMPLETE);
 }
 
+
 
 /**************************************
  * SCSI interface related section
@@ -3121,18 +2572,8 @@
 	scsi_id = hi->scsi_id[SCpnt->target];
 
 	/*
-	 * Save off the command if this is the initial bus scan... so that we can
-	 * complete it after we find all our sbp2 devices on the 1394 bus
-	 */
-	if (!no_bus_scan && !hi->initial_scsi_bus_scan_complete) {
-		hi->bus_scan_SCpnt = SCpnt;
-		hi->bus_scan_done = done;
-		return(0);
-	}
-
-	/*
-	 * If scsi_id is null, it means there is no device in this slot, so we should return 
-	 * selection timeout.
+	 * If scsi_id is null, it means there is no device in this slot,
+	 * so we should return selection timeout.
 	 */
 	if (!scsi_id) {
 		SCpnt->result = DID_NO_CONNECT << 16;
@@ -3141,7 +2582,8 @@
 	}
 
 	/*
-	 * Until we handle multiple luns, just return selection time-out to any IO directed at non-zero LUNs
+	 * Until we handle multiple luns, just return selection time-out
+	 * to any IO directed at non-zero LUNs
 	 */
 	if (SCpnt->lun) {
 		SCpnt->result = DID_NO_CONNECT << 16;
@@ -3150,7 +2592,8 @@
 	}
 
 	/*
-	 * Check for request sense command, and handle it here (autorequest sense)
+	 * Check for request sense command, and handle it here
+	 * (autorequest sense)
 	 */
 	if (SCpnt->cmnd[0] == REQUEST_SENSE) {
 		SBP2_DEBUG("sbp2: REQUEST_SENSE");
@@ -3161,9 +2604,10 @@
 	}
 
 	/*
-	 * Check to see if there is a command in progress and just return busy (to be queued later)
+	 * Check to see if there is a command in progress and just return
+	 * busy (to be queued later)
 	 */
-	if (hi->bus_reset_in_progress) {
+	if (!hpsb_node_entry_valid(scsi_id->ne)) {
 		SBP2_ERR("sbp2: Bus reset in progress - rejecting command");
 		SCpnt->result = DID_BUS_BUSY << 16;
 		done (SCpnt);
@@ -3184,9 +2628,11 @@
 }
 
 /*
- * This function is called in order to complete all outstanding SBP-2 commands (in case of resets, etc.). 
+ * This function is called in order to complete all outstanding SBP-2
+ * commands (in case of resets, etc.).
  */
-static void sbp2scsi_complete_all_commands(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, 
+static void sbp2scsi_complete_all_commands(struct sbp2scsi_host_info *hi,
+					   struct scsi_id_instance_data *scsi_id, 
 					   u32 status)
 {
 	struct list_head *lh;
@@ -3210,7 +2656,7 @@
 }
 
 /*
- * This function is called in order to complete a regular SBP-2 command. 
+ * This function is called in order to complete a regular SBP-2 command.
  */
 static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, u32 scsi_status,
 				      Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
@@ -3226,10 +2672,11 @@
 	}
 
 	/*
-	 * If a bus reset is in progress and there was an error, don't complete the command,
-	 * just let it get retried at the end of the bus reset.
+	 * If a bus reset is in progress and there was an error, don't
+	 * complete the command, just let it get retried at the end of the
+	 * bus reset.
 	 */
-	if ((hi->bus_reset_in_progress) && (scsi_status != SBP2_SCSI_STATUS_GOOD)) {
+	if (!hpsb_node_entry_valid(scsi_id->ne) && (scsi_status != SBP2_SCSI_STATUS_GOOD)) {
 		SBP2_ERR("sbp2: Bus reset in progress - retry command later");
 		return;
 	}
@@ -3283,9 +2730,10 @@
 	}
 
 	/*
-	 * One more quick hack (not enabled by default). Some sbp2 devices do not support 
-	 * mode sense. Turn-on this hack to allow the device to pass the sd driver's 
-	 * write-protect test (so that you can mount the device rw).
+	 * One more quick hack (not enabled by default). Some sbp2 devices
+	 * do not support mode sense. Turn-on this hack to allow the
+	 * device to pass the sd driver's write-protect test (so that you
+	 * can mount the device rw).
 	 */
 	if (mode_sense_hack && SCpnt->result != DID_OK && SCpnt->cmnd[0] == MODE_SENSE) {
 		SBP2_INFO("sbp2: Returning success to mode sense command");
@@ -3295,17 +2743,18 @@
 	}
 
 	/*
-	 * If a bus reset is in progress and there was an error, complete the command
-	 * as busy so that it will get retried.
+	 * If a bus reset is in progress and there was an error, complete
+	 * the command as busy so that it will get retried.
 	 */
-	if ((hi->bus_reset_in_progress) && (scsi_status != SBP2_SCSI_STATUS_GOOD)) {
+	if (!hpsb_node_entry_valid(scsi_id->ne) && (scsi_status != SBP2_SCSI_STATUS_GOOD)) {
 		SBP2_ERR("sbp2: Completing command with busy (bus reset)");
 		SCpnt->result = DID_BUS_BUSY << 16;
 	}
 
 	/*
-	 * If a unit attention occurs, return busy status so it gets retried... it could have happened because
-	 * of a 1394 bus reset or hot-plug...
+	 * If a unit attention occurs, return busy status so it gets
+	 * retried... it could have happened because of a 1394 bus reset
+	 * or hot-plug...
 	 */
 	if ((scsi_status == SBP2_SCSI_STATUS_CHECK_CONDITION) && (SCpnt->sense_buffer[2] == UNIT_ATTENTION)) {
 		SBP2_INFO("sbp2: UNIT ATTENTION - return busy");
@@ -3321,8 +2770,8 @@
 }
 
 /*
- * Called by scsi stack when something has really gone wrong.
- * Usually called when a command has timed-out for some reason. 
+ * Called by scsi stack when something has really gone wrong.  Usually
+ * called when a command has timed-out for some reason.
  */
 static int sbp2scsi_abort (Scsi_Cmnd *SCpnt) 
 {
@@ -3336,8 +2785,9 @@
 	if (scsi_id) {
 
 		/*
-		 * Right now, just return any matching command structures to the free pool (there may
-		 * be more than one because of broken up/linked commands).
+		 * Right now, just return any matching command structures
+		 * to the free pool (there may be more than one because of
+		 * broken up/linked commands).
 		 */
 		sbp2_spin_lock(&hi->sbp2_command_lock, flags);
 		do {
@@ -3445,10 +2895,6 @@
 		global_scsi_tpnt->use_clustering = DISABLE_CLUSTERING;
 	}
 
-	if (no_bus_scan) {
-		SBP2_ERR("sbp2: Initial scsi bus scan deferred (no_bus_scan = 1)");
-	}
-
 	if (mode_sense_hack) {
 		SBP2_ERR("sbp2: Mode sense emulation enabled (mode_sense_hack = 1)");
 	}
@@ -3457,21 +2903,19 @@
 
 	if (!sbp2_host_count) {
 		SBP2_ERR("sbp2: Please load the lower level IEEE-1394 driver (e.g. ohci1394) before sbp2...");
-		if (sbp2_hl_handle) {
-			hpsb_unregister_highlevel(sbp2_hl_handle);
-			sbp2_hl_handle = NULL;
-		}
+		sbp2_cleanup();
 	}
 
 	/*
-	 * Since we are returning this count, it means that sbp2 must be loaded "after" the 
-	 * host adapter module... 	 
+	 * Since we are returning this count, it means that sbp2 must be
+	 * loaded "after" the host adapter module...
 	 */
 	return(sbp2_host_count);
 }
 
 /*
- * This function is called from sbp2_add_host, and is where we register our scsi host
+ * This function is called from sbp2_add_host, and is where we register
+ * our scsi host
  */
 static void sbp2scsi_register_scsi_host(struct sbp2scsi_host_info *hi)
 {
@@ -3488,7 +2932,8 @@
 		shpnt = scsi_register (global_scsi_tpnt, sizeof(void *));
 
 		/*
-		 * If successful, save off a context (to be used when SCSI commands are received)
+		 * If successful, save off a context (to be used when SCSI
+		 * commands are received)
 		 */
 		if (shpnt) {
 			shpnt->hostdata[0] = (unsigned long)hi;
diff -urN linux-2.4.11-pre2/drivers/ieee1394/sbp2.h linux/drivers/ieee1394/sbp2.h
--- linux-2.4.11-pre2/drivers/ieee1394/sbp2.h	Sun Aug 12 12:39:02 2001
+++ linux/drivers/ieee1394/sbp2.h	Mon Dec  3 23:15:39 2001
@@ -36,13 +36,6 @@
 #define ORB_DIRECTION_READ_FROM_MEDIA   0x1
 #define ORB_DIRECTION_NO_DATA_TRANSFER  0x2
 
-#define SPEED_S100			0x0
-#define SPEED_S200			0x1
-#define SPEED_S400			0x2
-#define SPEED_S800			0x3
-#define SPEED_S1600			0x4
-#define SPEED_S3200			0x5
-
 /* 2^(MAX_PAYLOAD+1) = Maximum data transfer length */
 #define MAX_PAYLOAD_S100		0x7
 #define MAX_PAYLOAD_S200		0x8
@@ -232,8 +225,8 @@
  * Unit spec id and sw version entry for SBP-2 devices
  */
 
-#define SBP2_UNIT_SPEC_ID_ENTRY					0x1200609e
-#define SBP2_SW_VERSION_ENTRY					0x13010483
+#define SBP2_UNIT_SPEC_ID_ENTRY					0x0000609e
+#define SBP2_SW_VERSION_ENTRY					0x00010483
 
 /*
  * Miscellaneous general config rom related defines
@@ -243,11 +236,8 @@
 
 #define CONFIG_ROM_BASE_ADDRESS					0xfffff0000400ULL
 #define CONFIG_ROM_ROOT_DIR_BASE				0xfffff0000414ULL
-#define CONFIG_ROM_SIGNATURE_ADDRESS				0xfffff0000404ULL
 #define CONFIG_ROM_UNIT_DIRECTORY_OFFSET			0xfffff0000424ULL
 
-#define IEEE1394_CONFIG_ROM_SIGNATURE				0x31333934
-
 #define SBP2_128KB_BROKEN_FIRMWARE				0xa0b800
 #define SBP2_BROKEN_FIRMWARE_MAX_TRANSFER			0x20000
 
@@ -350,6 +340,8 @@
  * Information needed on a per scsi id basis (one for each sbp2 device)
  */
 struct scsi_id_instance_data {
+	/* SCSI ID */
+	int id;
 
 	/*
 	 * Various sbp2 specific structures
@@ -368,18 +360,15 @@
 	/*
 	 * Stuff we need to know about the sbp2 device itself
 	 */
-	u64 node_unique_id;
 	u64 sbp2_management_agent_addr;
 	u64 sbp2_command_block_agent_addr;
-	u32 node_id;
 	u32 speed_code;
 	u32 max_payload_size;
 
 	/*
 	 * Values pulled from the device's unit directory
 	 */
-	u32 sbp2_unit_spec_id;
-	u32 sbp2_unit_sw_version;
+	struct unit_directory *ud;
 	u32 sbp2_command_set_spec_id;
 	u32 sbp2_command_set;
 	u32 sbp2_unit_characteristics;
@@ -391,12 +380,6 @@
 	 */
 	wait_queue_head_t sbp2_login_wait;
 
-	/*
-	 * Flag noting whether the sbp2 device is currently validated (for use during
-	 * bus resets).
-	 */
-	u32 validated;
-
 	/* 
 	 * Pool of command orbs, so we can have more than overlapped command per id
 	 */
@@ -405,6 +388,8 @@
 	struct list_head sbp2_command_orb_completed;
 	u32 sbp2_total_command_orbs;
 
+	/* Node entry, as retrieved from NodeMgr entries */
+	struct node_entry *ne;
 };
 
 /*
@@ -425,22 +410,6 @@
 	spinlock_t sbp2_request_packet_lock;
 
 	/*
-	 * Flag indicating if a bus reset (or device detection) is in progress
-	 */
-	u32 bus_reset_in_progress;
-
-	/*
-	 * We currently use a kernel thread for dealing with bus resets and sbp2
-	 * device detection. We use this to wake up the thread when needed.
-	 */
-	wait_queue_head_t sbp2_detection_wait;
-
-	/* 
-	 * PID of sbp2 detection kernel thread 
-	 */
-	int sbp2_detection_pid;
-
-	/*
 	 * Lists keeping track of inuse/free sbp2_request_packets. These structures are
 	 * used for sending out sbp2 command and agent reset packets. We initially create
 	 * a pool of request packets so that we don't have to do any kmallocs while in critical
@@ -450,13 +419,6 @@
 	struct list_head sbp2_req_free;
 
 	/*
-	 * Stuff to keep track of the initial scsi bus scan (so that we don't miss it)
-	 */
-	u32 initial_scsi_bus_scan_complete;
-	Scsi_Cmnd *bus_scan_SCpnt;
-	void (*bus_scan_done)(Scsi_Cmnd *);
-
-	/*
 	 * Here is the pool of request packets. All the hpsb packets (for 1394 bus transactions)
 	 * are allocated at init and simply re-initialized when needed.
 	 */
@@ -476,9 +438,6 @@
 /*
  * Various utility prototypes
  */
-static int sbp2util_read_quadlet(struct sbp2scsi_host_info *hi, nodeid_t node, u64 addr,
-				 quadlet_t *buffer);
-static int sbp2util_unit_directory(struct sbp2scsi_host_info *hi, nodeid_t node, u64 *addr);
 static int sbp2util_create_request_packet_pool(struct sbp2scsi_host_info *hi);
 static void sbp2util_remove_request_packet_pool(struct sbp2scsi_host_info *hi);
 static struct sbp2_request_packet *sbp2util_allocate_write_request_packet(struct sbp2scsi_host_info *hi,
@@ -500,23 +459,19 @@
 /*
  * IEEE-1394 core driver related prototypes
  */
-static void sbp2_remove_unvalidated_devices(struct sbp2scsi_host_info *hi);
-static int sbp2_start_device(struct sbp2scsi_host_info *hi, int node_id);
-static int sbp2_check_device(struct sbp2scsi_host_info *hi, int node_id);
-static void sbp2_bus_reset_handler(void *context);
 static void sbp2_add_host(struct hpsb_host *host);
 static struct sbp2scsi_host_info *sbp2_find_host_info(struct hpsb_host *host);
 static void sbp2_remove_host(struct hpsb_host *host);
-static void sbp2_host_reset(struct hpsb_host *host);
-static int sbp2_detection_thread(void *__sbp2);
 int sbp2_init(void);
 void sbp2_cleanup(void);
-#if 0
-static int sbp2_handle_physdma_write(struct hpsb_host *host, int nodeid, quadlet_t *data,
-				     u64 addr, unsigned int length);
-static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid, quadlet_t *data,
-				    u64 addr, unsigned int length);
-#endif
+static int sbp2_probe(struct unit_directory *ud);
+static void sbp2_disconnect(struct unit_directory *ud);
+static void sbp2_update(struct unit_directory *ud);
+static int sbp2_start_device(struct sbp2scsi_host_info *hi, 
+			     struct unit_directory *ud);
+static void sbp2_remove_device(struct sbp2scsi_host_info *hi, 
+			       struct scsi_id_instance_data *scsi_id);
+
 /*
  * SBP-2 protocol related prototypes
  */
@@ -543,7 +498,7 @@
 static void sbp2_check_sbp2_command(unchar *cmd);
 static void sbp2_check_sbp2_response(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, 
 				     Scsi_Cmnd *SCpnt);
-static int sbp2_parse_unit_directory(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id);
+static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id);
 static int sbp2_set_busy_timeout(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id);
 static int sbp2_max_speed_and_size(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id);
 
diff -urN linux-2.4.11-pre2/drivers/ieee1394/video1394.c linux/drivers/ieee1394/video1394.c
--- linux-2.4.11-pre2/drivers/ieee1394/video1394.c	Mon Dec  3 23:15:29 2001
+++ linux/drivers/ieee1394/video1394.c	Mon Dec  3 23:15:39 2001
@@ -103,7 +103,7 @@
 	int ctxMatch;
 	wait_queue_head_t waitq;
         spinlock_t lock;
-	unsigned int syt_offset;
+    unsigned int syt_offset;
 	int flags;
 };
 
@@ -488,24 +488,27 @@
 	int i;
 
 	/* the first descriptor will read only 4 bytes */
-	ir_prg[0].control = (0x280C << 16) | 4;
+	ir_prg[0].control = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
+		DMA_CTL_BRANCH | 4;
 
 	/* set the sync flag */
 	if (flags & VIDEO1394_SYNC_FRAMES)
-		ir_prg[0].control |= 0x00030000;
+		ir_prg[0].control |= DMA_CTL_WAIT;
 
 	ir_prg[0].address = kvirt_to_bus(buf);
 	ir_prg[0].branchAddress =  (virt_to_bus(&(ir_prg[1].control)) 
 				    & 0xfffffff0) | 0x1;
 
 	/* the second descriptor will read PAGE_SIZE-4 bytes */
-	ir_prg[1].control = (0x280C << 16) | (PAGE_SIZE-4);
+	ir_prg[1].control = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
+		DMA_CTL_BRANCH | (PAGE_SIZE-4);
 	ir_prg[1].address = kvirt_to_bus(buf+4);
 	ir_prg[1].branchAddress =  (virt_to_bus(&(ir_prg[2].control)) 
 				    & 0xfffffff0) | 0x1;
 	
 	for (i=2;i<d->nb_cmd-1;i++) {
-		ir_prg[i].control = (0x280C << 16) | PAGE_SIZE;
+		ir_prg[i].control = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | 
+			DMA_CTL_BRANCH | PAGE_SIZE;
 		ir_prg[i].address = kvirt_to_bus(buf+(i-1)*PAGE_SIZE);
 
 		ir_prg[i].branchAddress =  
@@ -514,7 +517,8 @@
 	}
 
 	/* the last descriptor will generate an interrupt */
-	ir_prg[i].control = (0x283C << 16) | d->left_size;
+	ir_prg[i].control = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | 
+		DMA_CTL_IRQ | DMA_CTL_BRANCH | d->left_size;
 	ir_prg[i].address = kvirt_to_bus(buf+(i-1)*PAGE_SIZE);
 }
 	
@@ -691,13 +695,14 @@
 	d->last_used_cmd[n] = d->nb_cmd - 1;
 	for (i=0;i<d->nb_cmd;i++) {
 				 
-		it_prg[i].begin.control = OUTPUT_MORE_IMMEDIATE | 8 ;
+		it_prg[i].begin.control = DMA_CTL_OUTPUT_MORE |
+			DMA_CTL_IMMEDIATE | 8 ;
 		it_prg[i].begin.address = 0;
 		
 		it_prg[i].begin.status = 0;
 		
 		it_prg[i].data[0] = 
-			(DMA_SPEED_100 << 16) 
+			(SPEED_100 << 16) 
 			| (/* tag */ 1 << 14)
 			| (d->channel << 8) 
 			| (TCODE_ISO_DATA << 4);
@@ -706,7 +711,7 @@
 		it_prg[i].data[2] = 0;
 		it_prg[i].data[3] = 0;
 		
-		it_prg[i].end.control = 0x100c0000;
+		it_prg[i].end.control = DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH;
 		it_prg[i].end.address =
 			kvirt_to_bus(buf+i*d->packet_size);
 
@@ -721,7 +726,8 @@
 		}
 		else {
 			/* the last prg generates an interrupt */
-			it_prg[i].end.control |= 0x08300000 | d->left_size;
+			it_prg[i].end.control |= DMA_CTL_UPDATE | 
+				DMA_CTL_IRQ | d->left_size;
 			/* the last prg doesn't branch */
 			it_prg[i].begin.branchAddress = 0;
 			it_prg[i].end.branchAddress = 0;
@@ -761,7 +767,7 @@
 			size = packet_sizes[i];
 		}
 		it_prg[i].data[1] = size << 16; 
-		it_prg[i].end.control = 0x100c0000;
+		it_prg[i].end.control = DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH;
 
 		if (i < d->nb_cmd-1 && packet_sizes[i+1] != 0) {
 			it_prg[i].end.control |= size;
@@ -773,7 +779,8 @@
 				 & 0xfffffff0) | 0x3;
 		} else {
 			/* the last prg generates an interrupt */
-			it_prg[i].end.control |= 0x08300000 | size;
+			it_prg[i].end.control |= DMA_CTL_UPDATE | 
+				DMA_CTL_IRQ | size;
 			/* the last prg doesn't branch */
 			it_prg[i].begin.branchAddress = 0;
 			it_prg[i].end.branchAddress = 0;
@@ -1560,7 +1567,6 @@
 static void remove_card(struct video_card *video)
 {
 	int i;
-	unsigned long flags;
 
 	ohci1394_unregister_video(video->ohci, &video_tmpl);
 
@@ -1581,9 +1587,7 @@
 		}
 		kfree(video->it_context);
 	}
-	spin_lock_irqsave(&video1394_cards_lock, flags);
 	list_del(&video->list);
-	spin_unlock_irqrestore(&video1394_cards_lock, flags);
 
 	kfree(video);
 }
@@ -1607,7 +1611,7 @@
 			p = list_entry(lh, struct video_card, list);
 			if (p ->ohci == ohci) {
 				remove_card(p);
-				return;
+				break;
 			}
 		}
 	}
diff -urN linux-2.4.11-pre2/drivers/md/md.c linux/drivers/md/md.c
--- linux-2.4.11-pre2/drivers/md/md.c	Sat Sep 22 20:35:43 2001
+++ linux/drivers/md/md.c	Mon Dec  3 23:15:39 2001
@@ -140,7 +140,7 @@
  */
 dev_mapping_t mddev_map[MAX_MD_DEVS];
 
-void add_mddev_mapping (mddev_t * mddev, kdev_t dev, void *data)
+void add_mddev_mapping(mddev_t * mddev, kdev_t dev, void *data)
 {
 	unsigned int minor = MINOR(dev);
 
@@ -148,7 +148,7 @@
 		MD_BUG();
 		return;
 	}
-	if (mddev_map[minor].mddev != NULL) {
+	if (mddev_map[minor].mddev) {
 		MD_BUG();
 		return;
 	}
@@ -156,7 +156,7 @@
 	mddev_map[minor].data = data;
 }
 
-void del_mddev_mapping (mddev_t * mddev, kdev_t dev)
+void del_mddev_mapping(mddev_t * mddev, kdev_t dev)
 {
 	unsigned int minor = MINOR(dev);
 
@@ -172,7 +172,7 @@
 	mddev_map[minor].data = NULL;
 }
 
-static int md_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
+static int md_make_request(request_queue_t *q, int rw, struct buffer_head * bh)
 {
 	mddev_t *mddev = kdev_to_mddev(bh->b_rdev);
 
@@ -184,7 +184,7 @@
 	}
 }
 
-static mddev_t * alloc_mddev (kdev_t dev)
+static mddev_t * alloc_mddev(kdev_t dev)
 {
 	mddev_t *mddev;
 
@@ -195,7 +195,7 @@
 	mddev = (mddev_t *) kmalloc(sizeof(*mddev), GFP_KERNEL);
 	if (!mddev)
 		return NULL;
-		
+
 	memset(mddev, 0, sizeof(*mddev));
 
 	mddev->__minor = MINOR(dev);
@@ -245,7 +245,7 @@
 
 static MD_LIST_HEAD(device_names);
 
-char * partition_name (kdev_t dev)
+char * partition_name(kdev_t dev)
 {
 	struct gendisk *hd;
 	static char nomem [] = "<nomem>";
@@ -282,7 +282,7 @@
 	return dname->name;
 }
 
-static unsigned int calc_dev_sboffset (kdev_t dev, mddev_t *mddev,
+static unsigned int calc_dev_sboffset(kdev_t dev, mddev_t *mddev,
 						int persistent)
 {
 	unsigned int size = 0;
@@ -294,7 +294,7 @@
 	return size;
 }
 
-static unsigned int calc_dev_size (kdev_t dev, mddev_t *mddev, int persistent)
+static unsigned int calc_dev_size(kdev_t dev, mddev_t *mddev, int persistent)
 {
 	unsigned int size;
 
@@ -308,7 +308,7 @@
 	return size;
 }
 
-static unsigned int zoned_raid_size (mddev_t *mddev)
+static unsigned int zoned_raid_size(mddev_t *mddev)
 {
 	unsigned int mask;
 	mdk_rdev_t * rdev;
@@ -338,7 +338,7 @@
  * provide data have to be able to deal with loss of individual
  * disks, so they do their checking themselves.
  */
-int md_check_ordering (mddev_t *mddev)
+int md_check_ordering(mddev_t *mddev)
 {
 	int i, c;
 	mdk_rdev_t *rdev;
@@ -349,8 +349,8 @@
 	 */
 	ITERATE_RDEV(mddev,rdev,tmp) {
 		if (rdev->faulty) {
-			printk("md: md%d's device %s faulty, aborting.\n",
-				mdidx(mddev), partition_name(rdev->dev));
+			printk(KERN_ERR "md: md%d's device %s faulty, aborting.\n",
+			       mdidx(mddev), partition_name(rdev->dev));
 			goto abort;
 		}
 	}
@@ -364,7 +364,7 @@
 		goto abort;
 	}
 	if (mddev->nb_dev != mddev->sb->raid_disks) {
-		printk("md: md%d, array needs %d disks, has %d, aborting.\n",
+		printk(KERN_ERR "md: md%d, array needs %d disks, has %d, aborting.\n",
 			mdidx(mddev), mddev->sb->raid_disks, mddev->nb_dev);
 		goto abort;
 	}
@@ -378,13 +378,13 @@
 				c++;
 		}
 		if (!c) {
-			printk("md: md%d, missing disk #%d, aborting.\n",
-				mdidx(mddev), i);
+			printk(KERN_ERR "md: md%d, missing disk #%d, aborting.\n",
+			       mdidx(mddev), i);
 			goto abort;
 		}
 		if (c > 1) {
-			printk("md: md%d, too many disks #%d, aborting.\n",
-				mdidx(mddev), i);
+			printk(KERN_ERR "md: md%d, too many disks #%d, aborting.\n",
+			       mdidx(mddev), i);
 			goto abort;
 		}
 	}
@@ -393,7 +393,7 @@
 	return 1;
 }
 
-static void remove_descriptor (mdp_disk_t *disk, mdp_super_t *sb)
+static void remove_descriptor(mdp_disk_t *disk, mdp_super_t *sb)
 {
 	if (disk_active(disk)) {
 		sb->working_disks--;
@@ -426,7 +426,7 @@
 #define BAD_CSUM KERN_WARNING \
 "md: invalid superblock checksum on %s\n"
 
-static int alloc_array_sb (mddev_t * mddev)
+static int alloc_array_sb(mddev_t * mddev)
 {
 	if (mddev->sb) {
 		MD_BUG();
@@ -440,14 +440,14 @@
 	return 0;
 }
 
-static int alloc_disk_sb (mdk_rdev_t * rdev)
+static int alloc_disk_sb(mdk_rdev_t * rdev)
 {
 	if (rdev->sb)
 		MD_BUG();
 
 	rdev->sb = (mdp_super_t *) __get_free_page(GFP_KERNEL);
 	if (!rdev->sb) {
-		printk (OUT_OF_MEM);
+		printk(OUT_OF_MEM);
 		return -EINVAL;
 	}
 	md_clear_page(rdev->sb);
@@ -455,7 +455,7 @@
 	return 0;
 }
 
-static void free_disk_sb (mdk_rdev_t * rdev)
+static void free_disk_sb(mdk_rdev_t * rdev)
 {
 	if (rdev->sb) {
 		free_page((unsigned long) rdev->sb);
@@ -468,7 +468,7 @@
 	}
 }
 
-static int read_disk_sb (mdk_rdev_t * rdev)
+static int read_disk_sb(mdk_rdev_t * rdev)
 {
 	int ret = -EINVAL;
 	struct buffer_head *bh = NULL;
@@ -479,15 +479,14 @@
 	if (!rdev->sb) {
 		MD_BUG();
 		goto abort;
-	}	
-	
+	}
+
 	/*
 	 * Calculate the position of the superblock,
 	 * it's at the end of the disk
 	 */
 	sb_offset = calc_dev_sboffset(rdev->dev, rdev->mddev, 1);
 	rdev->sb_offset = sb_offset;
-	printk("(read) %s's sb offset: %ld", partition_name(dev), sb_offset);
 	fsync_dev(dev);
 	set_blocksize (dev, MD_SB_BYTES);
 	bh = bread (dev, sb_offset / MD_SB_BLOCKS, MD_SB_BYTES);
@@ -496,10 +495,10 @@
 		sb = (mdp_super_t *) bh->b_data;
 		memcpy (rdev->sb, sb, MD_SB_BYTES);
 	} else {
-		printk (NO_SB,partition_name(rdev->dev));
+		printk(NO_SB,partition_name(rdev->dev));
 		goto abort;
 	}
-	printk(" [events: %08lx]\n", (unsigned long)rdev->sb->events_lo);
+	printk(KERN_INFO " [events: %08lx]\n", (unsigned long)rdev->sb->events_lo);
 	ret = 0;
 abort:
 	if (bh)
@@ -507,7 +506,7 @@
 	return ret;
 }
 
-static unsigned int calc_sb_csum (mdp_super_t * sb)
+static unsigned int calc_sb_csum(mdp_super_t * sb)
 {
 	unsigned int disk_csum, csum;
 
@@ -522,7 +521,7 @@
  * Check one RAID superblock for generic plausibility
  */
 
-static int check_disk_sb (mdk_rdev_t * rdev)
+static int check_disk_sb(mdk_rdev_t * rdev)
 {
 	mdp_super_t *sb;
 	int ret = -EINVAL;
@@ -534,13 +533,12 @@
 	}
 
 	if (sb->md_magic != MD_SB_MAGIC) {
-		printk (BAD_MAGIC, partition_name(rdev->dev));
+		printk(BAD_MAGIC, partition_name(rdev->dev));
 		goto abort;
 	}
 
 	if (sb->md_minor >= MAX_MD_DEVS) {
-		printk (BAD_MINOR, partition_name(rdev->dev),
-							sb->md_minor);
+		printk(BAD_MINOR, partition_name(rdev->dev), sb->md_minor);
 		goto abort;
 	}
 
@@ -590,7 +588,7 @@
 static MD_LIST_HEAD(all_raid_disks);
 static MD_LIST_HEAD(pending_raid_disks);
 
-static void bind_rdev_to_array (mdk_rdev_t * rdev, mddev_t * mddev)
+static void bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
 {
 	mdk_rdev_t *same_pdev;
 
@@ -603,16 +601,16 @@
 		printk( KERN_WARNING
 "md%d: WARNING: %s appears to be on the same physical disk as %s. True\n"
 "     protection against single-disk failure might be compromised.\n",
- 			mdidx(mddev), partition_name(rdev->dev),
+			mdidx(mddev), partition_name(rdev->dev),
 				partition_name(same_pdev->dev));
-		
+
 	md_list_add(&rdev->same_set, &mddev->disks);
 	rdev->mddev = mddev;
 	mddev->nb_dev++;
-	printk("md: bind<%s,%d>\n", partition_name(rdev->dev), mddev->nb_dev);
+	printk(KERN_INFO "md: bind<%s,%d>\n", partition_name(rdev->dev), mddev->nb_dev);
 }
 
-static void unbind_rdev_from_array (mdk_rdev_t * rdev)
+static void unbind_rdev_from_array(mdk_rdev_t * rdev)
 {
 	if (!rdev->mddev) {
 		MD_BUG();
@@ -621,7 +619,7 @@
 	md_list_del(&rdev->same_set);
 	MD_INIT_LIST_HEAD(&rdev->same_set);
 	rdev->mddev->nb_dev--;
-	printk("md: unbind<%s,%d>\n", partition_name(rdev->dev),
+	printk(KERN_INFO "md: unbind<%s,%d>\n", partition_name(rdev->dev),
 						 rdev->mddev->nb_dev);
 	rdev->mddev = NULL;
 }
@@ -633,13 +631,13 @@
  * inode is not enough, the SCSI module usage code needs
  * an explicit open() on the device]
  */
-static int lock_rdev (mdk_rdev_t *rdev)
+static int lock_rdev(mdk_rdev_t *rdev)
 {
 	int err = 0;
 	struct block_device *bdev;
 
 	bdev = bdget(rdev->dev);
-	if (bdev == NULL)
+	if (!bdev)
 		return -ENOMEM;
 	err = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_RAW);
 	if (!err)
@@ -647,7 +645,7 @@
 	return err;
 }
 
-static void unlock_rdev (mdk_rdev_t *rdev)
+static void unlock_rdev(mdk_rdev_t *rdev)
 {
 	struct block_device *bdev = rdev->bdev;
 	rdev->bdev = NULL;
@@ -656,11 +654,11 @@
 	blkdev_put(bdev, BDEV_RAW);
 }
 
-void md_autodetect_dev (kdev_t dev);
+void md_autodetect_dev(kdev_t dev);
 
-static void export_rdev (mdk_rdev_t * rdev)
+static void export_rdev(mdk_rdev_t * rdev)
 {
-	printk("md: export_rdev(%s)\n",partition_name(rdev->dev));
+	printk(KERN_INFO "md: export_rdev(%s)\n",partition_name(rdev->dev));
 	if (rdev->mddev)
 		MD_BUG();
 	unlock_rdev(rdev);
@@ -668,7 +666,8 @@
 	md_list_del(&rdev->all);
 	MD_INIT_LIST_HEAD(&rdev->all);
 	if (rdev->pending.next != &rdev->pending) {
-		printk("md: (%s was pending)\n",partition_name(rdev->dev));
+		printk(KERN_INFO "md: (%s was pending)\n",
+			partition_name(rdev->dev));
 		md_list_del(&rdev->pending);
 		MD_INIT_LIST_HEAD(&rdev->pending);
 	}
@@ -680,13 +679,13 @@
 	kfree(rdev);
 }
 
-static void kick_rdev_from_array (mdk_rdev_t * rdev)
+static void kick_rdev_from_array(mdk_rdev_t * rdev)
 {
 	unbind_rdev_from_array(rdev);
 	export_rdev(rdev);
 }
 
-static void export_array (mddev_t *mddev)
+static void export_array(mddev_t *mddev)
 {
 	struct md_list_head *tmp;
 	mdk_rdev_t *rdev;
@@ -708,7 +707,7 @@
 		MD_BUG();
 }
 
-static void free_mddev (mddev_t *mddev)
+static void free_mddev(mddev_t *mddev)
 {
 	if (!mddev) {
 		MD_BUG();
@@ -751,45 +750,47 @@
 {
 	int i;
 
-	printk("md:  SB: (V:%d.%d.%d) ID:<%08x.%08x.%08x.%08x> CT:%08x\n",
+	printk(KERN_INFO "md:  SB: (V:%d.%d.%d) ID:<%08x.%08x.%08x.%08x> CT:%08x\n",
 		sb->major_version, sb->minor_version, sb->patch_version,
 		sb->set_uuid0, sb->set_uuid1, sb->set_uuid2, sb->set_uuid3,
 		sb->ctime);
-	printk("md:     L%d S%08d ND:%d RD:%d md%d LO:%d CS:%d\n", sb->level,
+	printk(KERN_INFO "md:     L%d S%08d ND:%d RD:%d md%d LO:%d CS:%d\n", sb->level,
 		sb->size, sb->nr_disks, sb->raid_disks, sb->md_minor,
 		sb->layout, sb->chunk_size);
-	printk("md:     UT:%08x ST:%d AD:%d WD:%d FD:%d SD:%d CSUM:%08x E:%08lx\n",
+	printk(KERN_INFO "md:     UT:%08x ST:%d AD:%d WD:%d FD:%d SD:%d CSUM:%08x E:%08lx\n",
 		sb->utime, sb->state, sb->active_disks, sb->working_disks,
 		sb->failed_disks, sb->spare_disks,
 		sb->sb_csum, (unsigned long)sb->events_lo);
 
+	printk(KERN_INFO);
 	for (i = 0; i < MD_SB_DISKS; i++) {
 		mdp_disk_t *desc;
 
 		desc = sb->disks + i;
-		if (desc->number || desc->major || desc->minor || desc->raid_disk || (desc->state && (desc->state != 4))) {
+		if (desc->number || desc->major || desc->minor ||
+		    desc->raid_disk || (desc->state && (desc->state != 4))) {
 			printk("     D %2d: ", i);
 			print_desc(desc);
 		}
 	}
-	printk("md:     THIS: ");
+	printk(KERN_INFO "md:     THIS: ");
 	print_desc(&sb->this_disk);
 
 }
 
 static void print_rdev(mdk_rdev_t *rdev)
 {
-	printk("md: rdev %s: O:%s, SZ:%08ld F:%d DN:%d ",
+	printk(KERN_INFO "md: rdev %s: O:%s, SZ:%08ld F:%d DN:%d ",
 		partition_name(rdev->dev), partition_name(rdev->old_dev),
 		rdev->size, rdev->faulty, rdev->desc_nr);
 	if (rdev->sb) {
-		printk("md: rdev superblock:\n");
+		printk(KERN_INFO "md: rdev superblock:\n");
 		print_sb(rdev->sb);
 	} else
-		printk("md: no rdev superblock!\n");
+		printk(KERN_INFO "md: no rdev superblock!\n");
 }
 
-void md_print_devices (void)
+void md_print_devices(void)
 {
 	struct md_list_head *tmp, *tmp2;
 	mdk_rdev_t *rdev;
@@ -818,7 +819,7 @@
 	printk("\n");
 }
 
-static int sb_equal ( mdp_super_t *sb1, mdp_super_t *sb2)
+static int sb_equal(mdp_super_t *sb1, mdp_super_t *sb2)
 {
 	int ret;
 	mdp_super_t *tmp1, *tmp2;
@@ -867,7 +868,7 @@
 	return 0;
 }
 
-static mdk_rdev_t * find_rdev_all (kdev_t dev)
+static mdk_rdev_t * find_rdev_all(kdev_t dev)
 {
 	struct md_list_head *tmp;
 	mdk_rdev_t *rdev;
@@ -908,8 +909,8 @@
 	dev = rdev->dev;
 	sb_offset = calc_dev_sboffset(dev, rdev->mddev, 1);
 	if (rdev->sb_offset != sb_offset) {
-		printk("%s's sb offset has changed from %ld to %ld, skipping\n",
-			partition_name(dev), rdev->sb_offset, sb_offset);
+		printk(KERN_INFO "%s's sb offset has changed from %ld to %ld, skipping\n",
+		       partition_name(dev), rdev->sb_offset, sb_offset);
 		goto skip;
 	}
 	/*
@@ -919,12 +920,12 @@
 	 */
 	size = calc_dev_size(dev, rdev->mddev, 1);
 	if (size != rdev->size) {
-		printk("%s's size has changed from %ld to %ld since import, skipping\n",
-			partition_name(dev), rdev->size, size);
+		printk(KERN_INFO "%s's size has changed from %ld to %ld since import, skipping\n",
+		       partition_name(dev), rdev->size, size);
 		goto skip;
 	}
 
-	printk("(write) %s's sb offset: %ld\n", partition_name(dev), sb_offset);
+	printk(KERN_INFO "(write) %s's sb offset: %ld\n", partition_name(dev), sb_offset);
 	fsync_dev(dev);
 	set_blocksize(dev, MD_SB_BYTES);
 	bh = getblk(dev, sb_offset / MD_SB_BLOCKS, MD_SB_BYTES);
@@ -945,7 +946,7 @@
 skip:
 	return 0;
 }
-#undef GETBLK_FAILED 
+#undef GETBLK_FAILED
 
 static void set_this_disk(mddev_t *mddev, mdk_rdev_t *rdev)
 {
@@ -1025,7 +1026,7 @@
 
 	err = 0;
 	ITERATE_RDEV(mddev,rdev,tmp) {
-		printk("md: ");
+		printk(KERN_INFO "md: ");
 		if (rdev->faulty)
 			printk("(skipping faulty ");
 		if (rdev->alias_device)
@@ -1041,10 +1042,10 @@
 	}
 	if (err) {
 		if (--count) {
-			printk("md: errors occurred during superblock update, repeating\n");
+			printk(KERN_ERR "md: errors occurred during superblock update, repeating\n");
 			goto repeat;
 		}
-		printk("md: excessive errors occurred during superblock update, exiting\n");
+		printk(KERN_ERR "md: excessive errors occurred during superblock update, exiting\n");
 	}
 	return 0;
 }
@@ -1059,7 +1060,7 @@
  *
  * a faulty rdev _never_ has rdev->sb set.
  */
-static int md_import_device (kdev_t newdev, int on_disk)
+static int md_import_device(kdev_t newdev, int on_disk)
 {
 	int err;
 	mdk_rdev_t *rdev;
@@ -1070,13 +1071,13 @@
 
 	rdev = (mdk_rdev_t *) kmalloc(sizeof(*rdev), GFP_KERNEL);
 	if (!rdev) {
-		printk("md: could not alloc mem for %s!\n", partition_name(newdev));
+		printk(KERN_ERR "md: could not alloc mem for %s!\n", partition_name(newdev));
 		return -ENOMEM;
 	}
 	memset(rdev, 0, sizeof(*rdev));
 
 	if (is_mounted(newdev)) {
-		printk("md: can not import %s, has active inodes!\n",
+		printk(KERN_WARNING "md: can not import %s, has active inodes!\n",
 			partition_name(newdev));
 		err = -EBUSY;
 		goto abort_free;
@@ -1087,7 +1088,7 @@
 
 	rdev->dev = newdev;
 	if (lock_rdev(rdev)) {
-		printk("md: could not lock %s, zero-size? Marking faulty.\n",
+		printk(KERN_ERR "md: could not lock %s, zero-size? Marking faulty.\n",
 			partition_name(newdev));
 		err = -EINVAL;
 		goto abort_free;
@@ -1099,7 +1100,7 @@
 	if (blk_size[MAJOR(newdev)])
 		size = blk_size[MAJOR(newdev)][MINOR(newdev)];
 	if (!size) {
-		printk("md: %s has zero size, marking faulty!\n",
+		printk(KERN_WARNING "md: %s has zero size, marking faulty!\n",
 				partition_name(newdev));
 		err = -EINVAL;
 		goto abort_free;
@@ -1107,13 +1108,13 @@
 
 	if (on_disk) {
 		if ((err = read_disk_sb(rdev))) {
-			printk("md: could not read %s's sb, not importing!\n",
-					partition_name(newdev));
+			printk(KERN_WARNING "md: could not read %s's sb, not importing!\n",
+			       partition_name(newdev));
 			goto abort_free;
 		}
 		if ((err = check_disk_sb(rdev))) {
-			printk("md: %s has invalid sb, not importing!\n",
-					partition_name(newdev));
+			printk(KERN_WARNING "md: %s has invalid sb, not importing!\n",
+			       partition_name(newdev));
 			goto abort_free;
 		}
 
@@ -1162,7 +1163,7 @@
 #define UNKNOWN_LEVEL KERN_ERR \
 "md: md%d: unsupported raid level %d\n"
 
-static int analyze_sbs (mddev_t * mddev)
+static int analyze_sbs(mddev_t * mddev)
 {
 	int out_of_date = 0, i, first;
 	struct md_list_head *tmp, *tmp2;
@@ -1197,7 +1198,7 @@
 			continue;
 		}
 		if (!sb_equal(sb, rdev->sb)) {
-			printk (INCONSISTENT, partition_name(rdev->dev));
+			printk(INCONSISTENT, partition_name(rdev->dev));
 			kick_rdev_from_array(rdev);
 			continue;
 		}
@@ -1227,7 +1228,8 @@
 					rdev->sb->events_hi--;
 		}
 
-		printk("md: %s's event counter: %08lx\n", partition_name(rdev->dev),
+		printk(KERN_INFO "md: %s's event counter: %08lx\n",
+		       partition_name(rdev->dev),
 			(unsigned long)rdev->sb->events_lo);
 		if (!freshest) {
 			freshest = rdev;
@@ -1246,7 +1248,7 @@
 	}
 	if (out_of_date) {
 		printk(OUT_OF_DATE);
-		printk("md: freshest: %s\n", partition_name(freshest->dev));
+		printk(KERN_INFO "md: freshest: %s\n", partition_name(freshest->dev));
 	}
 	memcpy (sb, freshest->sb, sizeof(*sb));
 
@@ -1265,7 +1267,7 @@
 		ev2 = md_event(sb);
 		++ev1;
 		if (ev1 < ev2) {
-			printk("md: kicking non-fresh %s from array!\n",
+			printk(KERN_WARNING "md: kicking non-fresh %s from array!\n",
 						partition_name(rdev->dev));
 			kick_rdev_from_array(rdev);
 			continue;
@@ -1291,7 +1293,8 @@
 			((ev1 == ev2) || (ev1 == ev3))) {
 			mdp_disk_t *desc;
 
-			printk("md: device name has changed from %s to %s since last import!\n", partition_name(rdev->old_dev), partition_name(rdev->dev));
+			printk(KERN_WARNING "md: device name has changed from %s to %s since last import!\n",
+			       partition_name(rdev->old_dev), partition_name(rdev->dev));
 			if (rdev->desc_nr == -1) {
 				MD_BUG();
 				goto abort;
@@ -1338,7 +1341,7 @@
 			ITERATE_RDEV(mddev,rdev,tmp) {
 				if (rdev->desc_nr != desc->number)
 					continue;
-				printk("md%d: kicking faulty %s!\n",
+				printk(KERN_WARNING "md%d: kicking faulty %s!\n",
 					mdidx(mddev),partition_name(rdev->dev));
 				kick_rdev_from_array(rdev);
 				found = 1;
@@ -1347,7 +1350,7 @@
 			if (!found) {
 				if (dev == MKDEV(0,0))
 					continue;
-				printk("md%d: removing former faulty %s!\n",
+				printk(KERN_WARNING "md%d: removing former faulty %s!\n",
 					mdidx(mddev), partition_name(dev));
 			}
 			remove_descriptor(desc, sb);
@@ -1389,7 +1392,8 @@
 		if (found)
 			continue;
 
-		printk("md%d: former device %s is unavailable, removing from array!\n", mdidx(mddev), partition_name(dev));
+		printk(KERN_WARNING "md%d: former device %s is unavailable, removing from array!\n",
+		       mdidx(mddev), partition_name(dev));
 		remove_descriptor(desc, sb);
 	}
 
@@ -1436,7 +1440,7 @@
 				first = 0;
 		}
 	}
- 
+
 	/*
 	 * Kick all rdevs that are not in the
 	 * descriptor array:
@@ -1445,7 +1449,7 @@
 		if (rdev->desc_nr == -1)
 			kick_rdev_from_array(rdev);
 	}
- 
+
 	/*
 	 * Do a final reality check.
 	 */
@@ -1484,14 +1488,14 @@
 	if (sb->major_version != MD_MAJOR_VERSION ||
 			sb->minor_version > MD_MINOR_VERSION) {
 
-		printk (OLD_VERSION, mdidx(mddev), sb->major_version,
+		printk(OLD_VERSION, mdidx(mddev), sb->major_version,
 				sb->minor_version, sb->patch_version);
 		goto abort;
 	}
 
 	if ((sb->state != (1 << MD_SB_CLEAN)) && ((sb->level == 1) ||
 			(sb->level == 4) || (sb->level == 5)))
-		printk (NOT_CLEAN_IGNORE, mdidx(mddev));
+		printk(NOT_CLEAN_IGNORE, mdidx(mddev));
 
 	return 0;
 abort:
@@ -1503,7 +1507,7 @@
 #undef OLD_VERSION
 #undef OLD_LEVEL
 
-static int device_size_calculation (mddev_t * mddev)
+static int device_size_calculation(mddev_t * mddev)
 {
 	int data_disks = 0, persistent;
 	unsigned int readahead;
@@ -1526,7 +1530,7 @@
 		}
 		rdev->size = calc_dev_size(rdev->dev, mddev, persistent);
 		if (rdev->size < sb->chunk_size / 1024) {
-			printk (KERN_WARNING
+			printk(KERN_WARNING
 				"md: Dev %s smaller than chunk_size: %ldk < %dk\n",
 				partition_name(rdev->dev),
 				rdev->size, sb->chunk_size / 1024);
@@ -1560,7 +1564,7 @@
 			data_disks = sb->raid_disks-1;
 			break;
 		default:
-			printk (UNKNOWN_LEVEL, mdidx(mddev), sb->level);
+			printk(UNKNOWN_LEVEL, mdidx(mddev), sb->level);
 			goto abort;
 	}
 	if (!md_size[mdidx(mddev)])
@@ -1599,7 +1603,7 @@
 #define BAD_CHUNKSIZE KERN_ERR \
 "no chunksize specified, see 'man raidtab'\n"
 
-static int do_md_run (mddev_t * mddev)
+static int do_md_run(mddev_t * mddev)
 {
 	int pnum, err;
 	int chunk_size;
@@ -1663,7 +1667,8 @@
 		}
 	} else
 		if (chunk_size)
-			printk(KERN_INFO "md: RAID level %d does not need chunksize! Continuing anyway.\n", mddev->sb->level);
+			printk(KERN_INFO "md: RAID level %d does not need chunksize! Continuing anyway.\n",
+			       mddev->sb->level);
 
 	if (pnum >= MAX_PERSONALITY) {
 		MD_BUG();
@@ -1700,7 +1705,7 @@
 			continue;
 		invalidate_device(rdev->dev, 1);
 		if (get_hardsect_size(rdev->dev)
-			> md_hardsect_sizes[mdidx(mddev)]) 
+			> md_hardsect_sizes[mdidx(mddev)])
 			md_hardsect_sizes[mdidx(mddev)] =
 				get_hardsect_size(rdev->dev);
 	}
@@ -1711,7 +1716,7 @@
 
 	err = mddev->pers->run(mddev);
 	if (err) {
-		printk("md: pers->run() failed ...\n");
+		printk(KERN_ERR "md: pers->run() failed ...\n");
 		mddev->pers = NULL;
 		return -EINVAL;
 	}
@@ -1736,7 +1741,7 @@
 
 #define OUT(x) do { err = (x); goto out; } while (0)
 
-static int restart_array (mddev_t *mddev)
+static int restart_array(mddev_t *mddev)
 {
 	int err = 0;
 
@@ -1753,7 +1758,7 @@
 		mddev->ro = 0;
 		set_device_ro(mddev_to_kdev(mddev), 0);
 
-		printk (KERN_INFO
+		printk(KERN_INFO
 			"md: md%d switched to read-write mode.\n", mdidx(mddev));
 		/*
 		 * Kick recovery or resync if necessary
@@ -1762,7 +1767,7 @@
 		if (mddev->pers->restart_resync)
 			mddev->pers->restart_resync(mddev);
 	} else {
-		printk (KERN_ERR "md: md%d has no personality assigned.\n",
+		printk(KERN_ERR "md: md%d has no personality assigned.\n",
 			mdidx(mddev));
 		err = -EINVAL;
 	}
@@ -1776,15 +1781,15 @@
 #define	STILL_IN_USE \
 "md: md%d still in use.\n"
 
-static int do_md_stop (mddev_t * mddev, int ro)
+static int do_md_stop(mddev_t * mddev, int ro)
 {
 	int err = 0, resync_interrupted = 0;
 	kdev_t dev = mddev_to_kdev(mddev);
 
- 	if (atomic_read(&mddev->active)>1) {
- 		printk(STILL_IN_USE, mdidx(mddev));
- 		OUT(-EBUSY);
- 	}
+	if (atomic_read(&mddev->active)>1) {
+		printk(STILL_IN_USE, mdidx(mddev));
+		OUT(-EBUSY);
+	}
 
 	if (mddev->pers) {
 		/*
@@ -1831,7 +1836,7 @@
 			 * interrupted.
 			 */
 			if (!mddev->recovery_running && !resync_interrupted) {
-				printk("md: marking sb clean...\n");
+				printk(KERN_INFO "md: marking sb clean...\n");
 				mddev->sb->state |= 1 << MD_SB_CLEAN;
 			}
 			md_update_sb(mddev);
@@ -1844,12 +1849,11 @@
 	 * Free resources if final stop
 	 */
 	if (!ro) {
-		printk (KERN_INFO "md: md%d stopped.\n", mdidx(mddev));
+		printk(KERN_INFO "md: md%d stopped.\n", mdidx(mddev));
 		free_mddev(mddev);
 
 	} else
-		printk (KERN_INFO
-			"md: md%d switched to read-only mode.\n", mdidx(mddev));
+		printk(KERN_INFO "md: md%d switched to read-only mode.\n", mdidx(mddev));
 out:
 	return err;
 }
@@ -1859,7 +1863,7 @@
 /*
  * We have to safely support old arrays too.
  */
-int detect_old_array (mdp_super_t *sb)
+int detect_old_array(mdp_super_t *sb)
 {
 	if (sb->major_version > 0)
 		return 0;
@@ -1870,7 +1874,7 @@
 }
 
 
-static void autorun_array (mddev_t *mddev)
+static void autorun_array(mddev_t *mddev)
 {
 	mdk_rdev_t *rdev;
 	struct md_list_head *tmp;
@@ -1881,7 +1885,7 @@
 		return;
 	}
 
-	printk("md: running: ");
+	printk(KERN_INFO "md: running: ");
 
 	ITERATE_RDEV(mddev,rdev,tmp) {
 		printk("<%s>", partition_name(rdev->dev));
@@ -1890,7 +1894,7 @@
 
 	err = do_md_run (mddev);
 	if (err) {
-		printk("md :do_md_run() returned %d\n", err);
+		printk(KERN_WARNING "md :do_md_run() returned %d\n", err);
 		/*
 		 * prevent the writeback of an unrunnable array
 		 */
@@ -1911,7 +1915,7 @@
  *
  * If "unit" is allocated, then bump its reference count
  */
-static void autorun_devices (kdev_t countdev)
+static void autorun_devices(kdev_t countdev)
 {
 	struct md_list_head candidates;
 	struct md_list_head *tmp;
@@ -1920,20 +1924,22 @@
 	kdev_t md_kdev;
 
 
-	printk("md: autorun ...\n");
+	printk(KERN_INFO "md: autorun ...\n");
 	while (pending_raid_disks.next != &pending_raid_disks) {
 		rdev0 = md_list_entry(pending_raid_disks.next,
 					 mdk_rdev_t, pending);
 
-		printk("md: considering %s ...\n", partition_name(rdev0->dev));
+		printk(KERN_INFO "md: considering %s ...\n", partition_name(rdev0->dev));
 		MD_INIT_LIST_HEAD(&candidates);
 		ITERATE_RDEV_PENDING(rdev,tmp) {
 			if (uuid_equal(rdev0, rdev)) {
 				if (!sb_equal(rdev0->sb, rdev->sb)) {
-					printk("md: %s has same UUID as %s, but superblocks differ ...\n", partition_name(rdev->dev), partition_name(rdev0->dev));
+					printk(KERN_WARNING
+					       "md: %s has same UUID as %s, but superblocks differ ...\n",
+					       partition_name(rdev->dev), partition_name(rdev0->dev));
 					continue;
 				}
-				printk("md:  adding %s ...\n", partition_name(rdev->dev));
+				printk(KERN_INFO "md:  adding %s ...\n", partition_name(rdev->dev));
 				md_list_del(&rdev->pending);
 				md_list_add(&rdev->pending, &candidates);
 			}
@@ -1946,20 +1952,20 @@
 		md_kdev = MKDEV(MD_MAJOR, rdev0->sb->md_minor);
 		mddev = kdev_to_mddev(md_kdev);
 		if (mddev) {
-			printk("md: md%d already running, cannot run %s\n",
-				 mdidx(mddev), partition_name(rdev0->dev));
+			printk(KERN_WARNING "md: md%d already running, cannot run %s\n",
+			       mdidx(mddev), partition_name(rdev0->dev));
 			ITERATE_RDEV_GENERIC(candidates,pending,rdev,tmp)
 				export_rdev(rdev);
 			continue;
 		}
 		mddev = alloc_mddev(md_kdev);
- 		if (mddev == NULL) {
- 			printk("md: cannot allocate memory for md drive.\n");
- 			break;
- 		}
- 		if (md_kdev == countdev)
- 			atomic_inc(&mddev->active);
-		printk("md: created md%d\n", mdidx(mddev));
+		if (!mddev) {
+			printk(KERN_ERR "md: cannot allocate memory for md drive.\n");
+			break;
+		}
+		if (md_kdev == countdev)
+			atomic_inc(&mddev->active);
+		printk(KERN_INFO "md: created md%d\n", mdidx(mddev));
 		ITERATE_RDEV_GENERIC(candidates,pending,rdev,tmp) {
 			bind_rdev_to_array(rdev, mddev);
 			md_list_del(&rdev->pending);
@@ -1967,7 +1973,7 @@
 		}
 		autorun_array(mddev);
 	}
-	printk("md: ... autorun DONE.\n");
+	printk(KERN_INFO "md: ... autorun DONE.\n");
 }
 
 /*
@@ -2002,14 +2008,14 @@
 #define AUTORUNNING KERN_INFO \
 "md: auto-running md%d.\n"
 
-static int autostart_array (kdev_t startdev, kdev_t countdev)
+static int autostart_array(kdev_t startdev, kdev_t countdev)
 {
 	int err = -EINVAL, i;
 	mdp_super_t *sb = NULL;
 	mdk_rdev_t *start_rdev = NULL, *rdev;
 
 	if (md_import_device(startdev, 1)) {
-		printk("md: could not import %s!\n", partition_name(startdev));
+		printk(KERN_WARNING "md: could not import %s!\n", partition_name(startdev));
 		goto abort;
 	}
 
@@ -2019,7 +2025,7 @@
 		goto abort;
 	}
 	if (start_rdev->faulty) {
-		printk("md: can not autostart based on faulty %s!\n",
+		printk(KERN_WARNING "md: can not autostart based on faulty %s!\n",
 						partition_name(startdev));
 		goto abort;
 	}
@@ -2029,7 +2035,9 @@
 
 	err = detect_old_array(sb);
 	if (err) {
-		printk("md: array version is too old to be autostarted, use raidtools 0.90 mkraid --upgrade\nto upgrade the array without data loss!\n");
+		printk(KERN_WARNING "md: array version is too old to be autostarted ,"
+		       "use raidtools 0.90 mkraid --upgrade to upgrade the array "
+		       "without data loss!\n");
 		goto abort;
 	}
 
@@ -2045,7 +2053,8 @@
 		if (dev == startdev)
 			continue;
 		if (md_import_device(dev, 1)) {
-			printk("md: could not import %s, trying to run array nevertheless.\n", partition_name(dev));
+			printk(KERN_WARNING "md: could not import %s, trying to run array nevertheless.\n",
+			       partition_name(dev));
 			continue;
 		}
 		rdev = find_rdev_all(dev);
@@ -2078,7 +2087,7 @@
 #undef AUTORUNNING
 
 
-static int get_version (void * arg)
+static int get_version(void * arg)
 {
 	mdu_version_t ver;
 
@@ -2093,7 +2102,7 @@
 }
 
 #define SET_FROM_SB(x) info.x = mddev->sb->x
-static int get_array_info (mddev_t * mddev, void * arg)
+static int get_array_info(mddev_t * mddev, void * arg)
 {
 	mdu_array_info_t info;
 
@@ -2131,7 +2140,7 @@
 #undef SET_FROM_SB
 
 #define SET_FROM_SB(x) info.x = mddev->sb->disks[nr].x
-static int get_disk_info (mddev_t * mddev, void * arg)
+static int get_disk_info(mddev_t * mddev, void * arg)
 {
 	mdu_disk_info_t info;
 	unsigned int nr;
@@ -2160,7 +2169,7 @@
 
 #define SET_SB(x) mddev->sb->disks[nr].x = info->x
 
-static int add_new_disk (mddev_t * mddev, mdu_disk_info_t *info)
+static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
 {
 	int err, size, persistent;
 	mdk_rdev_t *rdev;
@@ -2169,15 +2178,15 @@
 	dev = MKDEV(info->major,info->minor);
 
 	if (find_rdev_all(dev)) {
-		printk("md: device %s already used in a RAID array!\n",
-				partition_name(dev));
+		printk(KERN_WARNING "md: device %s already used in a RAID array!\n",
+		       partition_name(dev));
 		return -EBUSY;
 	}
 	if (!mddev->sb) {
 		/* expecting a device which has a superblock */
 		err = md_import_device(dev, 1);
 		if (err) {
-			printk("md: md_import_device returned %d\n", err);
+			printk(KERN_WARNING "md: md_import_device returned %d\n", err);
 			return -EINVAL;
 		}
 		rdev = find_rdev_all(dev);
@@ -2189,12 +2198,14 @@
 			mdk_rdev_t *rdev0 = md_list_entry(mddev->disks.next,
 							mdk_rdev_t, same_set);
 			if (!uuid_equal(rdev0, rdev)) {
-				printk("md: %s has different UUID to %s\n", partition_name(rdev->dev), partition_name(rdev0->dev));
+				printk(KERN_WARNING "md: %s has different UUID to %s\n",
+				       partition_name(rdev->dev), partition_name(rdev0->dev));
 				export_rdev(rdev);
 				return -EINVAL;
 			}
 			if (!sb_equal(rdev0->sb, rdev->sb)) {
-				printk("md: %s has same UUID but different superblock to %s\n", partition_name(rdev->dev), partition_name(rdev0->dev));
+				printk(KERN_WARNING "md: %s has same UUID but different superblock to %s\n",
+				       partition_name(rdev->dev), partition_name(rdev0->dev));
 				export_rdev(rdev);
 				return -EINVAL;
 			}
@@ -2219,7 +2230,7 @@
 	if ((info->state & (1<<MD_DISK_FAULTY))==0) {
 		err = md_import_device (dev, 0);
 		if (err) {
-			printk("md: error, md_import_device() returned %d\n", err);
+			printk(KERN_WARNING "md: error, md_import_device() returned %d\n", err);
 			return -EINVAL;
 		}
 		rdev = find_rdev_all(dev);
@@ -2235,7 +2246,7 @@
 
 		persistent = !mddev->sb->not_persistent;
 		if (!persistent)
-			printk("md: nonpersistent superblock ...\n");
+			printk(KERN_INFO "md: nonpersistent superblock ...\n");
 
 		size = calc_dev_size(dev, mddev, persistent);
 		rdev->sb_offset = calc_dev_sboffset(dev, mddev, persistent);
@@ -2253,24 +2264,24 @@
 }
 #undef SET_SB
 
-static int hot_generate_error (mddev_t * mddev, kdev_t dev)
+static int hot_generate_error(mddev_t * mddev, kdev_t dev)
 {
 	struct request_queue *q;
 	mdk_rdev_t *rdev;
 	mdp_disk_t *disk;
- 
+
 	if (!mddev->pers)
 		return -ENODEV;
- 
-	printk("md: trying to generate %s error in md%d ... \n",
+
+	printk(KERN_INFO "md: trying to generate %s error in md%d ... \n",
 		partition_name(dev), mdidx(mddev));
- 
+
 	rdev = find_rdev(mddev, dev);
 	if (!rdev) {
 		MD_BUG();
 		return -ENXIO;
 	}
- 
+
 	if (rdev->desc_nr == -1) {
 		MD_BUG();
 		return -EINVAL;
@@ -2278,19 +2289,19 @@
 	disk = &mddev->sb->disks[rdev->desc_nr];
 	if (!disk_active(disk))
 		return -ENODEV;
- 
+
 	q = blk_get_queue(rdev->dev);
 	if (!q) {
 		MD_BUG();
 		return -ENODEV;
 	}
-	printk("md: okay, generating error!\n");
+	printk(KERN_INFO "md: okay, generating error!\n");
 //	q->oneshot_error = 1; // disabled for now
- 
+
 	return 0;
 }
 
-static int hot_remove_disk (mddev_t * mddev, kdev_t dev)
+static int hot_remove_disk(mddev_t * mddev, kdev_t dev)
 {
 	int err;
 	mdk_rdev_t *rdev;
@@ -2299,12 +2310,12 @@
 	if (!mddev->pers)
 		return -ENODEV;
 
-	printk("md: trying to remove %s from md%d ... \n",
+	printk(KERN_INFO "md: trying to remove %s from md%d ... \n",
 		partition_name(dev), mdidx(mddev));
 
 	if (!mddev->pers->diskop) {
-		printk("md%d: personality does not support diskops!\n",
-								 mdidx(mddev));
+		printk(KERN_WARNING "md%d: personality does not support diskops!\n",
+		       mdidx(mddev));
 		return -EINVAL;
 	}
 
@@ -2325,7 +2336,7 @@
 		MD_BUG();
 		return -EINVAL;
 	}
-	
+
 	err = mddev->pers->diskop(mddev, &disk, DISKOP_HOT_REMOVE_DISK);
 	if (err == -EBUSY) {
 		MD_BUG();
@@ -2343,12 +2354,12 @@
 
 	return 0;
 busy:
-	printk("md: cannot remove active disk %s from md%d ... \n",
+	printk(KERN_WARNING "md: cannot remove active disk %s from md%d ... \n",
 		partition_name(dev), mdidx(mddev));
 	return -EBUSY;
 }
 
-static int hot_add_disk (mddev_t * mddev, kdev_t dev)
+static int hot_add_disk(mddev_t * mddev, kdev_t dev)
 {
 	int i, err, persistent;
 	unsigned int size;
@@ -2358,12 +2369,12 @@
 	if (!mddev->pers)
 		return -ENODEV;
 
-	printk("md: trying to hot-add %s to md%d ... \n",
+	printk(KERN_INFO "md: trying to hot-add %s to md%d ... \n",
 		partition_name(dev), mdidx(mddev));
 
 	if (!mddev->pers->diskop) {
-		printk("md%d: personality does not support diskops!\n",
-								 mdidx(mddev));
+		printk(KERN_WARNING "md%d: personality does not support diskops!\n",
+		       mdidx(mddev));
 		return -EINVAL;
 	}
 
@@ -2371,7 +2382,7 @@
 	size = calc_dev_size(dev, mddev, persistent);
 
 	if (size < mddev->sb->size) {
-		printk("md%d: disk size %d blocks < array size %d\n",
+		printk(KERN_WARNING "md%d: disk size %d blocks < array size %d\n",
 				mdidx(mddev), size, mddev->sb->size);
 		return -ENOSPC;
 	}
@@ -2382,7 +2393,7 @@
 
 	err = md_import_device (dev, 0);
 	if (err) {
-		printk("md: error, md_import_device() returned %d\n", err);
+		printk(KERN_WARNING "md: error, md_import_device() returned %d\n", err);
 		return -EINVAL;
 	}
 	rdev = find_rdev_all(dev);
@@ -2391,7 +2402,7 @@
 		return -EINVAL;
 	}
 	if (rdev->faulty) {
-		printk("md: can not hot-add faulty %s disk to md%d!\n",
+		printk(KERN_WARNING "md: can not hot-add faulty %s disk to md%d!\n",
 				partition_name(dev), mdidx(mddev));
 		err = -EINVAL;
 		goto abort_export;
@@ -2416,7 +2427,8 @@
 			break;
 	}
 	if (i == MD_SB_DISKS) {
-		printk("md%d: can not hot-add to full array!\n", mdidx(mddev));
+		printk(KERN_WARNING "md%d: can not hot-add to full array!\n",
+		       mdidx(mddev));
 		err = -EBUSY;
 		goto abort_unbind_export;
 	}
@@ -2470,7 +2482,7 @@
 }
 
 #define SET_SB(x) mddev->sb->x = info->x
-static int set_array_info (mddev_t * mddev, mdu_array_info_t *info)
+static int set_array_info(mddev_t * mddev, mdu_array_info_t *info)
 {
 
 	if (alloc_array_sb(mddev))
@@ -2511,37 +2523,37 @@
 }
 #undef SET_SB
 
-static int set_disk_info (mddev_t * mddev, void * arg)
+static int set_disk_info(mddev_t * mddev, void * arg)
 {
-	printk("md: not yet");
+	printk(KERN_INFO "md: not yet");
 	return -EINVAL;
 }
 
-static int clear_array (mddev_t * mddev)
+static int clear_array(mddev_t * mddev)
 {
-	printk("md: not yet");
+	printk(KERN_INFO "md: not yet");
 	return -EINVAL;
 }
 
-static int write_raid_info (mddev_t * mddev)
+static int write_raid_info(mddev_t * mddev)
 {
-	printk("md: not yet");
+	printk(KERN_INFO "md: not yet");
 	return -EINVAL;
 }
 
-static int protect_array (mddev_t * mddev)
+static int protect_array(mddev_t * mddev)
 {
-	printk("md: not yet");
+	printk(KERN_INFO "md: not yet");
 	return -EINVAL;
 }
 
-static int unprotect_array (mddev_t * mddev)
+static int unprotect_array(mddev_t * mddev)
 {
-	printk("md: not yet");
+	printk(KERN_INFO "md: not yet");
 	return -EINVAL;
 }
 
-static int set_disk_faulty (mddev_t *mddev, kdev_t dev)
+static int set_disk_faulty(mddev_t *mddev, kdev_t dev)
 {
 	int ret;
 
@@ -2549,7 +2561,7 @@
 	return ret;
 }
 
-static int md_ioctl (struct inode *inode, struct file *file,
+static int md_ioctl(struct inode *inode, struct file *file,
 			unsigned int cmd, unsigned long arg)
 {
 	unsigned int minor;
@@ -2627,7 +2639,7 @@
 		case SET_ARRAY_INFO:
 		case START_ARRAY:
 			if (mddev) {
-				printk("md: array md%d already exists!\n",
+				printk(KERN_WARNING "md: array md%d already exists!\n",
 								mdidx(mddev));
 				err = -EEXIST;
 				goto abort;
@@ -2649,12 +2661,13 @@
 			 */
 			err = lock_mddev(mddev);
 			if (err) {
-				printk("md: ioctl, reason %d, cmd %d\n", err, cmd);
+				printk(KERN_WARNING "md: ioctl, reason %d, cmd %d\n",
+				       err, cmd);
 				goto abort;
 			}
 
 			if (mddev->sb) {
-				printk("md: array md%d already has a superblock!\n",
+				printk(KERN_WARNING "md: array md%d already has a superblock!\n",
 					mdidx(mddev));
 				err = -EBUSY;
 				goto abort_unlock;
@@ -2667,7 +2680,7 @@
 				}
 				err = set_array_info(mddev, &info);
 				if (err) {
-					printk("md: couldnt set array info. %d\n", err);
+					printk(KERN_WARNING "md: couldnt set array info. %d\n", err);
 					goto abort_unlock;
 				}
 			}
@@ -2679,7 +2692,7 @@
 			 */
 			err = autostart_array((kdev_t)arg, dev);
 			if (err) {
-				printk("md: autostart %s failed!\n",
+				printk(KERN_WARNING "md: autostart %s failed!\n",
 					partition_name((kdev_t)arg));
 				goto abort;
 			}
@@ -2698,7 +2711,7 @@
 	}
 	err = lock_mddev(mddev);
 	if (err) {
-		printk("md: ioctl lock interrupted, reason %d, cmd %d\n",err, cmd);
+		printk(KERN_INFO "md: ioctl lock interrupted, reason %d, cmd %d\n",err, cmd);
 		goto abort;
 	}
 	/* if we don't have a superblock yet, only ADD_NEW_DISK or STOP_ARRAY is allowed */
@@ -2839,7 +2852,9 @@
 		}
 
 		default:
-			printk(KERN_WARNING "md: %s(pid %d) used obsolete MD ioctl, upgrade your software to use new ictls.\n", current->comm, current->pid);
+			printk(KERN_WARNING "md: %s(pid %d) used obsolete MD ioctl, "
+			       "upgrade your software to use new ictls.\n",
+			       current->comm, current->pid);
 			err = -EINVAL;
 			goto abort_unlock;
 	}
@@ -2852,12 +2867,12 @@
 	return err;
 done:
 	if (err)
-		printk("md: huh12?\n");
+		MD_BUG();
 abort:
 	return err;
 }
 
-static int md_open (struct inode *inode, struct file *file)
+static int md_open(struct inode *inode, struct file *file)
 {
 	/*
 	 * Always succeed, but increment the usage count
@@ -2868,7 +2883,7 @@
 	return (0);
 }
 
-static int md_release (struct inode *inode, struct file * file)
+static int md_release(struct inode *inode, struct file * file)
 {
 	mddev_t *mddev = kdev_to_mddev(inode->i_rdev);
 	if (mddev)
@@ -2937,11 +2952,8 @@
 			run(thread->data);
 			run_task_queue(&tq_disk);
 		}
-		if (md_signal_pending(current)) {
-			printk("md: %8s(%d) flushing signals.\n", current->comm,
-				current->pid);
+		if (md_signal_pending(current))
 			md_flush_signals();
-		}
 	}
 	complete(thread->event);
 	return 0;
@@ -2954,22 +2966,22 @@
 	wake_up(&thread->wqueue);
 }
 
-mdk_thread_t *md_register_thread (void (*run) (void *),
+mdk_thread_t *md_register_thread(void (*run) (void *),
 						void *data, const char *name)
 {
 	mdk_thread_t *thread;
 	int ret;
 	struct completion event;
-	
+
 	thread = (mdk_thread_t *) kmalloc
 				(sizeof(mdk_thread_t), GFP_KERNEL);
 	if (!thread)
 		return NULL;
-	
+
 	memset(thread, 0, sizeof(mdk_thread_t));
 	md_init_waitqueue_head(&thread->wqueue);
 
-	init_completion(&event);	
+	init_completion(&event);
 	thread->event = &event;
 	thread->run = run;
 	thread->data = data;
@@ -2983,22 +2995,22 @@
 	return thread;
 }
 
-void md_interrupt_thread (mdk_thread_t *thread)
+void md_interrupt_thread(mdk_thread_t *thread)
 {
 	if (!thread->tsk) {
 		MD_BUG();
 		return;
 	}
-	printk("md: interrupting MD-thread pid %d\n", thread->tsk->pid);
+	dprintk("interrupting MD-thread pid %d\n", thread->tsk->pid);
 	send_sig(SIGKILL, thread->tsk, 1);
 }
 
-void md_unregister_thread (mdk_thread_t *thread)
+void md_unregister_thread(mdk_thread_t *thread)
 {
 	struct completion event;
 
 	init_completion(&event);
-	
+
 	thread->event = &event;
 	thread->run = NULL;
 	thread->name = NULL;
@@ -3007,7 +3019,7 @@
 	kfree(thread);
 }
 
-void md_recover_arrays (void)
+void md_recover_arrays(void)
 {
 	if (!md_recovery_thread) {
 		MD_BUG();
@@ -3017,12 +3029,15 @@
 }
 
 
-int md_error (mddev_t *mddev, kdev_t rdev)
+int md_error(mddev_t *mddev, kdev_t rdev)
 {
 	mdk_rdev_t * rrdev;
 
-/*	printk("md_error dev:(%d:%d), rdev:(%d:%d), (caller: %p,%p,%p,%p).\n",MAJOR(dev),MINOR(dev),MAJOR(rdev),MINOR(rdev), __builtin_return_address(0),__builtin_return_address(1),__builtin_return_address(2),__builtin_return_address(3));
- */
+	dprintk("md_error dev:(%d:%d), rdev:(%d:%d), (caller: %p,%p,%p,%p).\n",
+		MAJOR(dev),MINOR(dev),MAJOR(rdev),MINOR(rdev),
+		__builtin_return_address(0),__builtin_return_address(1),
+		__builtin_return_address(2),__builtin_return_address(3));
+
 	if (!mddev) {
 		MD_BUG();
 		return 0;
@@ -3030,7 +3045,7 @@
 	rrdev = find_rdev(mddev, rdev);
 	if (!rrdev || rrdev->faulty)
 		return 0;
-	if (mddev->pers->error_handler == NULL
+	if (!mddev->pers->error_handler
 			|| mddev->pers->error_handler(mddev,rdev) <= 0) {
 		free_disk_sb(rrdev);
 		rrdev->faulty = 1;
@@ -3048,7 +3063,7 @@
 	return 0;
 }
 
-static int status_unused (char * page)
+static int status_unused(char * page)
 {
 	int sz = 0, i = 0;
 	mdk_rdev_t *rdev;
@@ -3074,7 +3089,7 @@
 }
 
 
-static int status_resync (char * page, mddev_t * mddev)
+static int status_resync(char * page, mddev_t * mddev)
 {
 	int sz = 0;
 	unsigned long max_blocks, resync, res, dt, db, rt;
@@ -3084,7 +3099,7 @@
 
 	/*
 	 * Should not happen.
-	 */		
+	 */
 	if (!max_blocks) {
 		MD_BUG();
 		return 0;
@@ -3126,7 +3141,7 @@
 	if (!dt) dt++;
 	db = resync - (mddev->resync_mark_cnt/2);
 	rt = (dt * ((max_blocks-resync) / (db/100+1)))/100;
-	
+
 	sz += sprintf(page + sz, " finish=%lu.%lumin", rt / 60, (rt % 60)/6);
 
 	sz += sprintf(page + sz, " speed=%ldK/sec", db/dt);
@@ -3160,7 +3175,7 @@
 		sz += sprintf(page + sz, "md%d : %sactive", mdidx(mddev),
 						mddev->pers ? "" : "in");
 		if (mddev->pers) {
-			if (mddev->ro)	
+			if (mddev->ro)
 				sz += sprintf(page + sz, " (read-only)");
 			sz += sprintf(page + sz, " %s", mddev->pers->name);
 		}
@@ -3200,12 +3215,12 @@
 		}
 		sz += sprintf(page + sz, "\n");
 	}
-	sz += status_unused (page + sz);
+	sz += status_unused(page + sz);
 
 	return sz;
 }
 
-int register_md_personality (int pnum, mdk_personality_t *p)
+int register_md_personality(int pnum, mdk_personality_t *p)
 {
 	if (pnum >= MAX_PERSONALITY) {
 		MD_BUG();
@@ -3222,7 +3237,7 @@
 	return 0;
 }
 
-int unregister_md_personality (int pnum)
+int unregister_md_personality(int pnum)
 {
 	if (pnum >= MAX_PERSONALITY) {
 		MD_BUG();
@@ -3273,7 +3288,7 @@
 	sync_io[major][index] += nr_sectors;
 }
 
-static int is_mddev_idle (mddev_t *mddev)
+static int is_mddev_idle(mddev_t *mddev)
 {
 	mdk_rdev_t * rdev;
 	struct md_list_head *tmp;
@@ -3291,9 +3306,7 @@
 		curr_events = kstat.dk_drive_rblk[major][idx] +
 						kstat.dk_drive_wblk[major][idx] ;
 		curr_events -= sync_io[major][idx];
-//		printk("md: events(major: %d, idx: %d): %ld\n", major, idx, curr_events);
 		if ((curr_events - rdev->last_events) > 32) {
-//			printk("!I(%ld)%x", curr_events - rdev->last_events, rdev->dev);
 			rdev->last_events = curr_events;
 			idle = 0;
 		}
@@ -3321,7 +3334,7 @@
 	unsigned int max_sectors, currspeed,
 		j, window, err, serialize;
 	unsigned long mark[SYNC_MARKS];
-	unsigned long mark_cnt[SYNC_MARKS];	
+	unsigned long mark_cnt[SYNC_MARKS];
 	int last_mark,m;
 	struct md_list_head *tmp;
 	unsigned long last_check;
@@ -3337,7 +3350,9 @@
 		if (mddev2 == mddev)
 			continue;
 		if (mddev2->curr_resync && match_mddev_units(mddev,mddev2)) {
-			printk(KERN_INFO "md: delaying resync of md%d until md%d has finished resync (they share one or more physical units)\n", mdidx(mddev), mdidx(mddev2));
+			printk(KERN_INFO "md: delaying resync of md%d until md%d "
+			       "has finished resync (they share one or more physical units)\n",
+			       mdidx(mddev), mdidx(mddev2));
 			serialize = 1;
 			break;
 		}
@@ -3359,7 +3374,9 @@
 	printk(KERN_INFO "md: syncing RAID array md%d\n", mdidx(mddev));
 	printk(KERN_INFO "md: minimum _guaranteed_ reconstruction speed: %d KB/sec/disc.\n",
 						sysctl_speed_limit_min);
-	printk(KERN_INFO "md: using maximum available idle IO bandwith (but not more than %d KB/sec) for reconstruction.\n", sysctl_speed_limit_max);
+	printk(KERN_INFO "md: using maximum available idle IO bandwith "
+	       "(but not more than %d KB/sec) for reconstruction.\n",
+	       sysctl_speed_limit_max);
 
 	/*
 	 * Resync has low priority.
@@ -3379,7 +3396,8 @@
 	 * Tune reconstruction:
 	 */
 	window = MAX_READAHEAD*(PAGE_SIZE/512);
-	printk(KERN_INFO "md: using %dk window, over a total of %d blocks.\n",window/2,max_sectors/2);
+	printk(KERN_INFO "md: using %dk window, over a total of %d blocks.\n",
+	       window/2,max_sectors/2);
 
 	atomic_set(&mddev->recovery_active, 0);
 	init_waitqueue_head(&mddev->recovery_wait);
@@ -3401,14 +3419,14 @@
 			continue;
 
 		last_check = j;
-		
+
 		run_task_queue(&tq_disk);
 
 	repeat:
 		if (jiffies >= mark[last_mark] + SYNC_MARK_STEP ) {
 			/* step marks */
 			int next = (last_mark+1) % SYNC_MARKS;
-			
+
 			mddev->resync_mark = mark[next];
 			mddev->resync_mark_cnt = mark_cnt[next];
 			mark[next] = jiffies;
@@ -3422,7 +3440,7 @@
 			 * got a signal, exit.
 			 */
 			mddev->curr_resync = 0;
-			printk("md: md_do_sync() got signal ... exiting\n");
+			printk(KERN_INFO "md: md_do_sync() got signal ... exiting\n");
 			md_flush_signals();
 			err = -EINTR;
 			goto out;
@@ -3476,7 +3494,7 @@
  * of my root partition with the first 0.5 gigs of my /home partition ... so
  * i'm a bit nervous ;)
  */
-void md_do_recovery (void *data)
+void md_do_recovery(void *data)
 {
 	int err;
 	mddev_t *mddev;
@@ -3495,15 +3513,18 @@
 		if (sb->active_disks == sb->raid_disks)
 			continue;
 		if (!sb->spare_disks) {
-			printk(KERN_ERR "md%d: no spare disk to reconstruct array! -- continuing in degraded mode\n", mdidx(mddev));
+			printk(KERN_ERR "md%d: no spare disk to reconstruct array! "
+			       "-- continuing in degraded mode\n", mdidx(mddev));
 			continue;
 		}
 		/*
 		 * now here we get the spare and resync it.
 		 */
-		if ((spare = get_spare(mddev)) == NULL)
+		spare = get_spare(mddev);
+		if (!spare)
 			continue;
-		printk(KERN_INFO "md%d: resyncing spare disk %s to replace failed disk\n", mdidx(mddev), partition_name(MKDEV(spare->major,spare->minor)));
+		printk(KERN_INFO "md%d: resyncing spare disk %s to replace failed disk\n",
+		       mdidx(mddev), partition_name(MKDEV(spare->major,spare->minor)));
 		if (!mddev->pers->diskop)
 			continue;
 		if (mddev->pers->diskop(mddev, &spare, DISKOP_SPARE_WRITE))
@@ -3512,7 +3533,8 @@
 		mddev->recovery_running = 1;
 		err = md_do_sync(mddev, spare);
 		if (err == -EIO) {
-			printk(KERN_INFO "md%d: spare disk %s failed, skipping to next spare.\n", mdidx(mddev), partition_name(MKDEV(spare->major,spare->minor)));
+			printk(KERN_INFO "md%d: spare disk %s failed, skipping to next spare.\n",
+			       mdidx(mddev), partition_name(MKDEV(spare->major,spare->minor)));
 			if (!disk_faulty(spare)) {
 				mddev->pers->diskop(mddev,&spare,DISKOP_SPARE_INACTIVE);
 				mark_disk_faulty(spare);
@@ -3556,7 +3578,7 @@
 		goto restart;
 	}
 	printk(KERN_INFO "md: recovery thread finished ...\n");
-	
+
 }
 
 int md_notify_reboot(struct notifier_block *this,
@@ -3589,7 +3611,7 @@
 	priority:	INT_MAX, /* before any real devices */
 };
 
-static void md_geninit (void)
+static void md_geninit(void)
 {
 	int i;
 
@@ -3611,18 +3633,18 @@
 #endif
 }
 
-int md__init md_init (void)
+int md__init md_init(void)
 {
 	static char * name = "mdrecoveryd";
 	int minor;
-	
-	printk (KERN_INFO "md: md driver %d.%d.%d MAX_MD_DEVS=%d, MD_SB_DISKS=%d\n",
+
+	printk(KERN_INFO "md: md driver %d.%d.%d MAX_MD_DEVS=%d, MD_SB_DISKS=%d\n",
 			MD_MAJOR_VERSION, MD_MINOR_VERSION,
 			MD_PATCHLEVEL_VERSION, MAX_MD_DEVS, MD_SB_DISKS);
 
 	if (devfs_register_blkdev (MAJOR_NR, "md", &md_fops))
 	{
-		printk (KERN_ALERT "md: Unable to get major %d for md\n", MAJOR_NR);
+		printk(KERN_ALERT "md: Unable to get major %d for md\n", MAJOR_NR);
 		return (-1);
 	}
 	devfs_handle = devfs_mk_dir (NULL, "md", NULL);
@@ -3637,7 +3659,7 @@
 
 	/* forward all md request to md_make_request */
 	blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), md_make_request);
-	
+
 
 	read_ahead[MAJOR_NR] = INT_MAX;
 
@@ -3678,14 +3700,14 @@
 static int detected_devices[128];
 static int dev_cnt;
 
-void md_autodetect_dev (kdev_t dev)
+void md_autodetect_dev(kdev_t dev)
 {
 	if (dev_cnt >= 0 && dev_cnt < 127)
 		detected_devices[dev_cnt++] = dev;
 }
 
 
-static void autostart_arrays (void)
+static void autostart_arrays(void)
 {
 	mdk_rdev_t *rdev;
 	int i;
@@ -3753,21 +3775,22 @@
 	char *str1 = str;
 
 	if (get_option(&str, &minor) != 2) {	/* MD Number */
-		printk("md: Too few arguments supplied to md=.\n");
+		printk(KERN_WARNING "md: Too few arguments supplied to md=.\n");
 		return 0;
 	}
 	if (minor >= MAX_MD_DEVS) {
-		printk ("md: md=%d, Minor device number too high.\n", minor);
+		printk(KERN_WARNING "md: md=%d, Minor device number too high.\n", minor);
 		return 0;
 	} else if (md_setup_args.device_names[minor]) {
-		printk ("md: md=%d, Specified more then once. Replacing previous definition.\n", minor);
+		printk(KERN_WARNING "md: md=%d, Specified more then once. "
+		       "Replacing previous definition.\n", minor);
 	}
 	switch (get_option(&str, &level)) {	/* RAID Personality */
 	case 2: /* could be 0 or -1.. */
 		if (level == 0 || level == -1) {
 			if (get_option(&str, &factor) != 2 ||	/* Chunk Size */
 					get_option(&str, &fault) != 2) {
-				printk("md: Too few arguments supplied to md=.\n");
+				printk(KERN_WARNING "md: Too few arguments supplied to md=.\n");
 				return 0;
 			}
 			md_setup_args.pers[minor] = level;
@@ -3782,8 +3805,9 @@
 				pername = "raid0";
 				break;
 			default:
-				printk ("md: The kernel has not been configured for raid%d"
-					" support!\n", level);
+				printk(KERN_WARNING
+				       "md: The kernel has not been configured for raid%d support!\n",
+				       level);
 				return 0;
 			}
 			md_setup_args.pers[minor] = level;
@@ -3797,11 +3821,11 @@
 		md_setup_args.pers[minor] = 0;
 		pername="super-block";
 	}
-	
-	printk ("md: Will configure md%d (%s) from %s, below.\n",
+
+	printk(KERN_INFO "md: Will configure md%d (%s) from %s, below.\n",
 		minor, pername, str);
 	md_setup_args.device_names[minor] = str;
-			
+
 	return 1;
 }
 
@@ -3819,13 +3843,14 @@
 		mdu_disk_info_t dinfo;
 
 		if ((devname = md_setup_args.device_names[minor]) == 0)	continue;
-	
+
 		for (i = 0; i < MD_SB_DISKS && devname != 0; i++) {
 
 			char *p;
 			void *handle;
-	
-			if ((p = strchr(devname, ',')) != NULL)
+
+			p = strchr(devname, ',');
+			if (p)
 				*p++ = 0;
 
 			dev = name_to_kdev_t(devname);
@@ -3837,29 +3862,31 @@
 				dev = MKDEV(major, minor);
 			}
 			if (dev == 0) {
-				printk ("md: Unknown device name: %s\n", devname);
+				printk(KERN_WARNING "md: Unknown device name: %s\n", devname);
 				break;
 			}
-			
+
 			devices[i] = dev;
 			md_setup_args.device_set[minor] = 1;
-			
+
 			devname = p;
 		}
 		devices[i] = 0;
-		
+
 		if (md_setup_args.device_set[minor] == 0)
 			continue;
-		
+
 		if (mddev_map[minor].mddev) {
-			printk("md: Ignoring md=%d, already autodetected. (Use raid=noautodetect)\n", minor);
+			printk(KERN_WARNING
+			       "md: Ignoring md=%d, already autodetected. (Use raid=noautodetect)\n",
+			       minor);
 			continue;
 		}
-		printk("md: Loading md%d: %s\n", minor, md_setup_args.device_names[minor]);
-		
+		printk(KERN_INFO "md: Loading md%d: %s\n", minor, md_setup_args.device_names[minor]);
+
 		mddev = alloc_mddev(MKDEV(MD_MAJOR,minor));
-		if (mddev == NULL) {
-			printk("md: kmalloc failed - cannot start array %d\n", minor);
+		if (!mddev) {
+			printk(KERN_ERR "md: kmalloc failed - cannot start array %d\n", minor);
 			continue;
 		}
 		if (md_setup_args.pers[minor]) {
@@ -3905,7 +3932,7 @@
 		if (err) {
 			mddev->sb_dirty = 0;
 			do_md_stop(mddev, 0);
-			printk("md: starting md%d failed\n", minor);
+			printk(KERN_WARNING "md: starting md%d failed\n", minor);
 		}
 	}
 }
@@ -3950,7 +3977,7 @@
 
 #else /* It is a MODULE */
 
-int init_module (void)
+int init_module(void)
 {
 	return md_init();
 }
@@ -3965,7 +3992,7 @@
 }
 
 
-void cleanup_module (void)
+void cleanup_module(void)
 {
 	md_unregister_thread(md_recovery_thread);
 	devfs_unregister(devfs_handle);
@@ -3984,7 +4011,7 @@
 	blk_size[MAJOR_NR] = NULL;
 	max_readahead[MAJOR_NR] = NULL;
 	hardsect_size[MAJOR_NR] = NULL;
-	
+
 	free_device_names();
 
 }
diff -urN linux-2.4.11-pre2/drivers/net/8139too.c linux/drivers/net/8139too.c
--- linux-2.4.11-pre2/drivers/net/8139too.c	Mon Dec  3 23:15:30 2001
+++ linux/drivers/net/8139too.c	Mon Dec  3 23:15:39 2001
@@ -137,7 +137,7 @@
 */
 
 #define DRV_NAME	"8139too"
-#define DRV_VERSION	"0.9.18a"
+#define DRV_VERSION	"0.9.19"
 
 
 #include <linux/config.h>
@@ -620,6 +620,7 @@
 static struct net_device_stats *rtl8139_get_stats (struct net_device *dev);
 static inline u32 ether_crc (int length, unsigned char *data);
 static void rtl8139_set_rx_mode (struct net_device *dev);
+static void __set_rx_mode (struct net_device *dev);
 static void rtl8139_hw_start (struct net_device *dev);
 
 #ifdef USE_IO_OPS
@@ -962,6 +963,7 @@
 	dev->do_ioctl = netdev_ioctl;
 	dev->tx_timeout = rtl8139_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
+	dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM;
 
 	dev->irq = pdev->irq;
 
@@ -1725,18 +1727,21 @@
 	assert (tp->tx_info[entry].mapping == 0);
 
 	tp->tx_info[entry].skb = skb;
-	if ((long) skb->data & 3) {	/* Must use alignment buffer. */
-		/* tp->tx_info[entry].mapping = 0; */
-		memcpy (tp->tx_buf[entry], skb->data, skb->len);
-		dma_addr = tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs);
-	} else {
+	if ( !((unsigned long)skb->data & 3) && skb_shinfo(skb)->nr_frags == 0 &&
+			skb->ip_summed != CHECKSUM_HW) {
 		tp->xstats.tx_buf_mapped++;
 		tp->tx_info[entry].mapping =
 		    pci_map_single (tp->pci_dev, skb->data, skb->len,
 				    PCI_DMA_TODEVICE);
 		dma_addr = tp->tx_info[entry].mapping;
-	}
-
+	} else if (skb->len < TX_BUF_SIZE) {
+		skb_copy_and_csum_dev(skb, tp->tx_buf[entry]);
+		dma_addr = tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs);
+	} else {
+		dev_kfree_skb(skb);
+		tp->tx_info[entry].skb = NULL;
+		return 0;
+  	}
 	/* Note: the chip doesn't have auto-pad! */
 	spin_lock_irq(&tp->lock);
 	RTL_W32_F (TxAddr0 + (entry * 4), dma_addr);
@@ -1847,8 +1852,8 @@
 			    struct rtl8139_private *tp, void *ioaddr)
 {
 	u8 tmp8;
-	int tmp_work = 1000;
-
+	int tmp_work;
+    
 	DPRINTK ("%s: Ethernet frame had errors, status %8.8x.\n",
 	         dev->name, rx_status);
 	if (rx_status & RxTooLong) {
@@ -1863,33 +1868,52 @@
 		tp->stats.rx_length_errors++;
 	if (rx_status & RxCRCErr)
 		tp->stats.rx_crc_errors++;
+
 	/* Reset the receiver, based on RealTek recommendation. (Bug?) */
-	tp->cur_rx = 0;
 
 	/* disable receive */
-	RTL_W8 (ChipCmd, CmdTxEnb);
-
-	/* A.C.: Reset the multicast list. */
-	rtl8139_set_rx_mode (dev);
-
-	/* XXX potentially temporary hack to
-	 * restart hung receiver */
+	RTL_W8_F (ChipCmd, CmdTxEnb);
+	tmp_work = 200;
 	while (--tmp_work > 0) {
-		barrier();
+		udelay(1);
+		tmp8 = RTL_R8 (ChipCmd);
+		if (!(tmp8 & CmdRxEnb))
+			break;
+	}
+	if (tmp_work <= 0)
+		printk (KERN_WARNING PFX "rx stop wait too long\n");
+	/* restart receive */
+	tmp_work = 200;
+	while (--tmp_work > 0) {
+		RTL_W8_F (ChipCmd, CmdRxEnb | CmdTxEnb);
+		udelay(1);
 		tmp8 = RTL_R8 (ChipCmd);
 		if ((tmp8 & CmdRxEnb) && (tmp8 & CmdTxEnb))
 			break;
-		RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
 	}
-
-	/* G.S.: Re-enable receiver */
-	/* XXX temporary hack to work around receiver hang */
-	rtl8139_set_rx_mode (dev);
-
 	if (tmp_work <= 0)
 		printk (KERN_WARNING PFX "tx/rx enable wait too long\n");
-}
 
+	/* and reinitialize all rx related registers */
+	RTL_W8_F (Cfg9346, Cfg9346_Unlock);
+	/* Must enable Tx/Rx before setting transfer thresholds! */
+	RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
+
+	tp->rx_config = rtl8139_rx_config | AcceptBroadcast | AcceptMyPhys;
+	RTL_W32 (RxConfig, tp->rx_config);
+	tp->cur_rx = 0;
+
+	DPRINTK("init buffer addresses\n");
+
+	/* Lock Config[01234] and BMCR register writes */
+	RTL_W8 (Cfg9346, Cfg9346_Lock);
+
+	/* init Rx ring buffer DMA address */
+	RTL_W32_F (RxBuf, tp->rx_ring_dma);
+
+	/* A.C.: Reset the multicast list. */
+	__set_rx_mode (dev);
+}
 
 static void rtl8139_rx_interrupt (struct net_device *dev,
 				  struct rtl8139_private *tp, void *ioaddr)
@@ -2312,11 +2336,10 @@
 }
 
 
-static void rtl8139_set_rx_mode (struct net_device *dev)
+static void __set_rx_mode (struct net_device *dev)
 {
 	struct rtl8139_private *tp = dev->priv;
 	void *ioaddr = tp->mmio_addr;
-	unsigned long flags;
 	u32 mc_filter[2];	/* Multicast hash filter */
 	int i, rx_mode;
 	u32 tmp;
@@ -2353,22 +2376,28 @@
 		}
 	}
 
-	spin_lock_irqsave (&tp->lock, flags);
-
 	/* We can safely update without stopping the chip. */
 	tmp = rtl8139_rx_config | rx_mode;
 	if (tp->rx_config != tmp) {
-		RTL_W32 (RxConfig, tmp);
+		RTL_W32_F (RxConfig, tmp);
 		tp->rx_config = tmp;
 	}
 	RTL_W32_F (MAR0 + 0, mc_filter[0]);
 	RTL_W32_F (MAR0 + 4, mc_filter[1]);
 
-	spin_unlock_irqrestore (&tp->lock, flags);
 
 	DPRINTK ("EXIT\n");
 }
 
+static void rtl8139_set_rx_mode (struct net_device *dev)
+{
+	unsigned long flags;
+	struct rtl8139_private *tp = dev->priv;
+
+	spin_lock_irqsave (&tp->lock, flags);
+	__set_rx_mode(dev);
+	spin_unlock_irqrestore (&tp->lock, flags);
+}
 
 #ifdef CONFIG_PM
 
diff -urN linux-2.4.11-pre2/drivers/net/natsemi.c linux/drivers/net/natsemi.c
--- linux-2.4.11-pre2/drivers/net/natsemi.c	Mon Dec  3 23:15:30 2001
+++ linux/drivers/net/natsemi.c	Mon Dec  3 23:15:39 2001
@@ -65,6 +65,23 @@
 		* Wake on lan support (Erik Gilling)
 		* MXDMA fixes for serverworks
 		* EEPROM reload
+
+	version 1.0.9 (Manfred Spraul)
+		* Main change: fix lack of synchronize
+		netif_close/netif_suspend against a last interrupt
+		or packet.
+		* do not enable superflous interrupts (e.g. the
+		drivers relies on TxDone - TxIntr not needed)
+		* wait that the hardware has really stopped in close
+		and suspend.
+		* workaround for the (at least) gcc-2.95.1 compiler
+		problem. Also simplifies the code a bit.
+		* disable_irq() in tx_timeout - needed to protect
+		against rx interrupts.
+		* stop the nic before switching into silent rx mode
+		for wol (required according to docu).
+
+
 	TODO:
 	* big endian support with CFG:BEM instead of cpu_to_le32
 	* support for an external PHY
@@ -72,8 +89,8 @@
 */
 
 #define DRV_NAME	"natsemi"
-#define DRV_VERSION	"1.07+LK1.0.8"
-#define DRV_RELDATE	"Aug 07, 2001"
+#define DRV_VERSION	"1.07+LK1.0.9"
+#define DRV_RELDATE	"Oct 02, 2001"
 
 
 /* Updated to recommendations in pci-skeleton v2.03. */
@@ -345,6 +362,8 @@
 	IntrNormalSummary=0x025f, IntrAbnormalSummary=0xCD20,
 };
 
+#define DEFAULT_INTR 0x00f1cd65
+
 /* Bits in the RxMode register. */
 enum rx_mode_bits {
 	AcceptErr=0x20, AcceptRunt=0x10,
@@ -435,6 +454,7 @@
 static int  eeprom_read(long ioaddr, int location);
 static int  mdio_read(struct net_device *dev, int phy_id, int location);
 static void natsemi_reset(struct net_device *dev);
+static void natsemi_stop_rxtx(struct net_device *dev);
 static int  netdev_open(struct net_device *dev);
 static void check_link(struct net_device *dev);
 static void netdev_timer(unsigned long data);
@@ -460,6 +480,7 @@
 static int netdev_get_sopass(struct net_device *dev, u8 *data);
 static int netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd);
 static int netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd);
+static void enable_wol_mode(struct net_device *dev, int enable_intr);
 static int  netdev_close(struct net_device *dev);
 
 
@@ -709,7 +730,26 @@
 	}
 }
 
-
+static void natsemi_stop_rxtx(struct net_device *dev)
+{
+	long ioaddr = dev->base_addr;
+	int i;
+
+	writel(RxOff | TxOff, ioaddr + ChipCmd);
+	for(i=0;i< NATSEMI_HW_TIMEOUT;i++) {
+		if ((readl(ioaddr + ChipCmd) & (TxOn|RxOn)) == 0)
+			break;
+		udelay(5);
+	}
+	if (i==NATSEMI_HW_TIMEOUT && debug) {
+		printk(KERN_INFO "%s: Tx/Rx process did not stop in %d usec.\n",
+				dev->name, i*5);
+	} else if (debug > 2) {
+		printk(KERN_DEBUG "%s: Tx/Rx process stopped in %d usec.\n",
+				dev->name, i*5);
+	}
+}
+
 static int netdev_open(struct net_device *dev)
 {
 	struct netdev_private *np = dev->priv;
@@ -731,7 +771,9 @@
 		return i;
 	}
 	init_ring(dev);
+	spin_lock_irq(&np->lock);
 	init_registers(dev);
+	spin_unlock_irq(&np->lock);
 
 	netif_start_queue(dev);
 
@@ -865,7 +907,7 @@
 	__set_rx_mode(dev);
 
 	/* Enable interrupts by setting the interrupt mask. */
-	writel(IntrNormalSummary | IntrAbnormalSummary, ioaddr + IntrMask);
+ 	writel(DEFAULT_INTR, ioaddr + IntrMask);
 	writel(1, ioaddr + IntrEnable);
 
 	writel(RxOn | TxOn, ioaddr + ChipCmd);
@@ -892,30 +934,51 @@
 	add_timer(&np->timer);
 }
 
-static void tx_timeout(struct net_device *dev)
+static void dump_ring(struct net_device *dev)
 {
 	struct netdev_private *np = dev->priv;
-	long ioaddr = dev->base_addr;
 
-	printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
-		   " resetting...\n", dev->name, (int)readl(ioaddr + TxRingPtr));
-
-	{
+	if (debug > 2) {
 		int i;
-		printk(KERN_DEBUG "  Rx ring %p: ", np->rx_ring);
-		for (i = 0; i < RX_RING_SIZE; i++)
-			printk(" %8.8x", (unsigned int)np->rx_ring[i].cmd_status);
-		printk("\n"KERN_DEBUG"  Tx ring %p: ", np->tx_ring);
+		printk(KERN_DEBUG "  Tx ring at %8.8x:\n",
+			   (int)np->tx_ring);
 		for (i = 0; i < TX_RING_SIZE; i++)
-			printk(" %4.4x", np->tx_ring[i].cmd_status);
-		printk("\n");
+			printk(KERN_DEBUG " #%d desc. %8.8x %8.8x %8.8x.\n",
+				   i, np->tx_ring[i].next_desc,
+				   np->tx_ring[i].cmd_status, np->tx_ring[i].addr);
+		printk(KERN_DEBUG "  Rx ring %8.8x:\n",
+			   (int)np->rx_ring);
+		for (i = 0; i < RX_RING_SIZE; i++) {
+			printk(KERN_DEBUG " #%d desc. %8.8x %8.8x %8.8x.\n",
+				   i, np->rx_ring[i].next_desc,
+				   np->rx_ring[i].cmd_status, np->rx_ring[i].addr);
+		}
 	}
+}
+
+static void tx_timeout(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	long ioaddr = dev->base_addr;
+
+
+	disable_irq(dev->irq);
 	spin_lock_irq(&np->lock);
-	natsemi_reset(dev);
-	drain_ring(dev);
-	init_ring(dev);
-	init_registers(dev);
+	if (netif_device_present(dev)) {
+		printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
+			   " resetting...\n", dev->name, readl(ioaddr + IntrStatus));
+		dump_ring(dev);
+
+		natsemi_reset(dev);
+		drain_ring(dev);
+		init_ring(dev);
+		init_registers(dev);
+	} else {
+		printk(KERN_WARNING "%s: tx_timeout while in suspended state?\n",
+		   		dev->name);
+	}
 	spin_unlock_irq(&np->lock);
+	enable_irq(dev->irq);
 
 	dev->trans_start = jiffies;
 	np->stats.tx_errors++;
@@ -946,14 +1009,17 @@
 	np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
 	np->rx_head_desc = &np->rx_ring[0];
 
+	/* Please be carefull before changing this loop - at least gcc-2.95.1
+	 * miscompiles it otherwise.
+	 */
 	/* Initialize all Rx descriptors. */
 	for (i = 0; i < RX_RING_SIZE; i++) {
-		np->rx_ring[i].next_desc = cpu_to_le32(np->ring_dma+sizeof(struct netdev_desc)*(i+1));
+		np->rx_ring[i].next_desc = cpu_to_le32(np->ring_dma
+				+sizeof(struct netdev_desc)
+				 *((i+1)%RX_RING_SIZE));
 		np->rx_ring[i].cmd_status = cpu_to_le32(DescOwn);
 		np->rx_skbuff[i] = NULL;
 	}
-	/* Mark the last entry as wrapping the ring. */
-	np->rx_ring[i-1].next_desc = cpu_to_le32(np->ring_dma);
 
 	/* Fill in the Rx buffers.  Handle allocation failure gracefully. */
 	for (i = 0; i < RX_RING_SIZE; i++) {
@@ -965,18 +1031,18 @@
 		np->rx_dma[i] = pci_map_single(np->pci_dev,
 						skb->data, skb->len, PCI_DMA_FROMDEVICE);
 		np->rx_ring[i].addr = cpu_to_le32(np->rx_dma[i]);
-		np->rx_ring[i].cmd_status = cpu_to_le32(DescIntr | np->rx_buf_sz);
+		np->rx_ring[i].cmd_status = cpu_to_le32(np->rx_buf_sz);
 	}
 	np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
 
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		np->tx_skbuff[i] = NULL;
 		np->tx_ring[i].next_desc = cpu_to_le32(np->ring_dma
-					+sizeof(struct netdev_desc)*(i+1+RX_RING_SIZE));
+					+sizeof(struct netdev_desc)
+					 *((i+1)%TX_RING_SIZE+RX_RING_SIZE));
 		np->tx_ring[i].cmd_status = 0;
 	}
-	np->tx_ring[i-1].next_desc = cpu_to_le32(np->ring_dma
-					+sizeof(struct netdev_desc)*(RX_RING_SIZE));
+	dump_ring(dev);
 }
 
 static void drain_ring(struct net_device *dev)
@@ -1035,25 +1101,25 @@
 	np->tx_ring[entry].addr = cpu_to_le32(np->tx_dma[entry]);
 
 	spin_lock_irq(&np->lock);
-
-#if 0
-	np->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn | DescIntr | skb->len);
-#else
-	np->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn | skb->len);
-#endif
-	/* StrongARM: Explicitly cache flush np->tx_ring and skb->data,skb->len. */
-	wmb();
-	np->cur_tx++;
-	if (np->cur_tx - np->dirty_tx >= TX_QUEUE_LEN - 1) {
-		netdev_tx_done(dev);
-		if (np->cur_tx - np->dirty_tx >= TX_QUEUE_LEN - 1)
-			netif_stop_queue(dev);
+	
+	if (netif_device_present(dev)) {
+		np->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn | skb->len);
+		/* StrongARM: Explicitly cache flush np->tx_ring and skb->data,skb->len. */
+		wmb();
+		np->cur_tx++;
+		if (np->cur_tx - np->dirty_tx >= TX_QUEUE_LEN - 1) {
+			netdev_tx_done(dev);
+			if (np->cur_tx - np->dirty_tx >= TX_QUEUE_LEN - 1)
+				netif_stop_queue(dev);
+		}
+		/* Wake the potentially-idle transmit channel. */
+		writel(TxOn, dev->base_addr + ChipCmd);
+	} else {
+		dev_kfree_skb_irq(skb);
+		np->stats.tx_dropped++;
 	}
 	spin_unlock_irq(&np->lock);
 
-	/* Wake the potentially-idle transmit channel. */
-	writel(TxOn, dev->base_addr + ChipCmd);
-
 	dev->trans_start = jiffies;
 
 	if (debug > 4) {
@@ -1115,7 +1181,9 @@
 
 	ioaddr = dev->base_addr;
 	np = dev->priv;
-
+	
+	if (!netif_device_present(dev))
+		return;
 	do {
 		/* Reading automatically acknowledges all int sources. */
 		u32 intr_status = readl(ioaddr + IntrStatus);
@@ -1239,7 +1307,7 @@
 			np->rx_ring[entry].addr = cpu_to_le32(np->rx_dma[entry]);
 		}
 		np->rx_ring[entry].cmd_status =
-			cpu_to_le32(DescIntr | np->rx_buf_sz);
+			cpu_to_le32(np->rx_buf_sz);
 	}
 
 	/* Restart Rx engine if stopped. */
@@ -1305,11 +1373,13 @@
 
 	/* The chip only need report frame silently dropped. */
 	spin_lock_irq(&np->lock);
-	__get_stats(dev);
+ 	if (netif_running(dev) && netif_device_present(dev))
+ 		__get_stats(dev);
 	spin_unlock_irq(&np->lock);
 
 	return &np->stats;
 }
+
 /* The little-endian AUTODIN II ethernet CRC calculations.
    A big-endian version is also available.
    This is slow but compact code.  Do not use this routine for bulk data,
@@ -1408,7 +1478,8 @@
 {
 	struct netdev_private *np = dev->priv;
 	spin_lock_irq(&np->lock);
-	__set_rx_mode(dev);
+	if (netif_device_present(dev))
+		__set_rx_mode(dev);
 	spin_unlock_irq(&np->lock);
 }
 
@@ -1718,76 +1789,94 @@
 	}
 }
 
+static void enable_wol_mode(struct net_device *dev, int enable_intr)
+{
+	long ioaddr = dev->base_addr;
+
+	if (debug > 1)
+		printk(KERN_INFO "%s: remaining active for wake-on-lan\n", 
+			dev->name);
+	/* For WOL we must restart the rx process in silent mode.
+	 * Write NULL to the RxRingPtr. Only possible if
+	 * rx process is stopped
+	 */
+	writel(0, ioaddr + RxRingPtr);
+
+	/* and restart the rx process */
+	writel(RxOn, ioaddr + ChipCmd);
+
+	if (enable_intr) {
+		/* enable the WOL interrupt.
+		 * Could be used to send a netlink message.
+		 */
+		writel(readl(ioaddr + IntrMask) | WOLPkt, ioaddr + IntrMask);
+	}
+}
+
 static int netdev_close(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
 	struct netdev_private *np = dev->priv;
-	u32 wol = readl(ioaddr + WOLCmd) & WakeOptsSummary;
-	u32 clkrun;
 
 	netif_stop_queue(dev);
-	netif_carrier_off(dev);
 
 	if (debug > 1) {
-		printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.",
+ 		printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n",
 			   dev->name, (int)readl(ioaddr + ChipCmd));
 		printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d,  Rx %d / %d.\n",
 			   dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx);
 	}
 
-	/* Only shut down chip if wake on lan is not set */
-	if (!wol) {
-		/* Disable interrupts using the mask. */
-		writel(0, ioaddr + IntrMask);
-		writel(0, ioaddr + IntrEnable);
-		writel(2, ioaddr + StatsCtrl); 	/* Freeze Stats */
-	    
-		/* Stop the chip's Tx and Rx processes. */
-		writel(RxOff | TxOff, ioaddr + ChipCmd);
-	} else if (debug > 1) {
-		printk(KERN_INFO "%s: remaining active for wake-on-lan\n", 
-			dev->name);
-		/* spec says write 0 here */
-		writel(0, ioaddr + RxRingPtr);
-		/* allow wake-event interrupts now */
-		writel(readl(ioaddr + IntrMask) | WOLPkt, ioaddr + IntrMask);
-	}
 	del_timer_sync(&np->timer);
 
-#ifdef __i386__
-	if (debug > 2) {
-		int i;
-		printk("\n"KERN_DEBUG"  Tx ring at %8.8x:\n",
-			   (int)np->tx_ring);
-		for (i = 0; i < TX_RING_SIZE; i++)
-			printk(" #%d desc. %8.8x %8.8x.\n",
-				   i, np->tx_ring[i].cmd_status, np->tx_ring[i].addr);
-		printk("\n"KERN_DEBUG "  Rx ring %8.8x:\n",
-			   (int)np->rx_ring);
-		for (i = 0; i < RX_RING_SIZE; i++) {
-			printk(KERN_DEBUG " #%d desc. %8.8x %8.8x\n",
-				   i, np->rx_ring[i].cmd_status, np->rx_ring[i].addr);
-		}
-	}
-#endif /* __i386__ debugging only */
+	disable_irq(dev->irq);
+	spin_lock_irq(&np->lock);
+
+	writel(0, ioaddr + IntrEnable);
+	writel(0, ioaddr + IntrMask);
+	writel(2, ioaddr + StatsCtrl); 	/* Freeze Stats */
+	    
+	/* Stop the chip's Tx and Rx processes. */
+	natsemi_stop_rxtx(dev);
 
+	__get_stats(dev);
+	spin_unlock_irq(&np->lock);
+
+	/* race: shared irq and as most nics the DP83815
+	 * reports _all_ interrupt conditions in IntrStatus, even
+	 * disabled ones.
+	 * packet received after disable_irq, but before stop_rxtx
+	 * --> race. intr_handler would restart the rx process.
+	 * netif_device_{de,a}tach around {enable,free}_irq.
+	 */
+	netif_device_detach(dev);
+	enable_irq(dev->irq);
 	free_irq(dev->irq, dev);
+	netif_device_attach(dev);
+	/* clear the carrier last - an interrupt could reenable it otherwise */
+	netif_carrier_off(dev);
+
+	dump_ring(dev);
 	drain_ring(dev);
 	free_ring(dev);
 
-	clkrun = np->SavedClkRun;
-	if (wol) {
-		/* make sure to enable PME */
-		clkrun |= 0x100;
-	}
-
-	/* Restore PME enable bit */
-	writel(np->SavedClkRun, ioaddr + ClkRun);
-	
+	 {
+		u32 wol = readl(ioaddr + WOLCmd) & WakeOptsSummary;
+		u32 clkrun = np->SavedClkRun;
+		/* Restore PME enable bit */
+		if (wol) {
+			/* restart the NIC in WOL mode.
+			 * The nic must be stopped for this.
+			 */
+			enable_wol_mode(dev, 0);
+			/* make sure to enable PME */
+			clkrun |= 0x100;
+		}
+		writel(clkrun, ioaddr + ClkRun);
 #if 0
-	writel(0x0200, ioaddr + ChipConfig); /* Power down Xcvr. */
+		writel(0x0200, ioaddr + ChipConfig); /* Power down Xcvr. */
 #endif
-
+	}
 	return 0;
 }
 
@@ -1805,49 +1894,71 @@
 
 #ifdef CONFIG_PM
 
+/*
+ * suspend/resume synchronization:
+ * entry points:
+ *   netdev_open, netdev_close, netdev_ioctl, set_rx_mode, intr_handler,
+ *   start_tx, tx_timeout
+ * Reading from some registers can restart the nic!
+ * No function accesses the hardware without checking netif_device_present().
+ * 	the check occurs under spin_lock_irq(&np->lock);
+ * exceptions:
+ * 	* netdev_ioctl, netdev_open.
+ * 		net/core checks netif_device_present() before calling them.
+ * 	* netdev_close: doesn't hurt.
+ *	* netdev_timer: timer stopped by natsemi_suspend.
+ *	* intr_handler: doesn't acquire the spinlock. suspend calls
+ *		disable_irq() to enforce synchronization.
+ *
+ * netif_device_detach must occur under spin_unlock_irq(), interrupts from a detached
+ * device would cause an irq storm.
+ */
+
 static int natsemi_suspend (struct pci_dev *pdev, u32 state)
 {
 	struct net_device *dev = pci_get_drvdata (pdev);
 	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 
-	netif_device_detach(dev);
-	/* no more calls to tx_timeout, hard_start_xmit, set_rx_mode */
 	rtnl_lock();
-	rtnl_unlock();
-	/* noone within ->open */
 	if (netif_running (dev)) {
-		int i;
 		del_timer_sync(&np->timer);
-		/* no more link beat timer calls */
+
+		disable_irq(dev->irq);
 		spin_lock_irq(&np->lock);
-		writel(RxOff | TxOff, ioaddr + ChipCmd);
-		for(i=0;i< NATSEMI_HW_TIMEOUT;i++) {
-			if ((readl(ioaddr + ChipCmd) & (TxOn|RxOn)) == 0)
-				break;
-			udelay(5);
-		}
-		if (i==NATSEMI_HW_TIMEOUT && debug) {
-			printk(KERN_INFO "%s: Tx/Rx process did not stop in %d usec.\n",
-					dev->name, i*5);
-		} else if (debug > 2) {
-			printk(KERN_DEBUG "%s: Tx/Rx process stopped in %d usec.\n",
-					dev->name, i*5);
-		}
-		/* Tx and Rx processes stopped */
 
 		writel(0, ioaddr + IntrEnable);
-		/* all irq events disabled. */
-		spin_unlock_irq(&np->lock);
-
-		synchronize_irq();
+		natsemi_stop_rxtx(dev);
+		netif_stop_queue(dev);
+		netif_device_detach(dev);
 
+		spin_unlock_irq(&np->lock);
+		enable_irq(dev->irq);
+		
 		/* Update the error counts. */
 		__get_stats(dev);
 
 		/* pci_power_off(pdev, -1); */
 		drain_ring(dev);
+		{
+			u32 wol = readl(ioaddr + WOLCmd) & WakeOptsSummary;
+			u32 clkrun = np->SavedClkRun;
+			/* Restore PME enable bit */
+			if (wol) {
+				/* restart the NIC in WOL mode.
+				 * The nic must be stopped for this.
+				 * FIXME: use the WOL interupt 
+				 */
+				enable_wol_mode(dev, 0);
+				/* make sure to enable PME */
+				clkrun |= 0x100;
+			}
+			writel(clkrun, ioaddr + ClkRun);
+		}
+	} else {
+		netif_device_detach(dev);
 	}
+	rtnl_unlock();
 	return 0;
 }
 
@@ -1857,18 +1968,27 @@
 	struct net_device *dev = pci_get_drvdata (pdev);
 	struct netdev_private *np = dev->priv;
 
-	if (netif_running (dev)) {
+	rtnl_lock();
+	if (netif_device_present(dev))
+		goto out;
+	if (netif_running(dev)) {
 		pci_enable_device(pdev);
 	/*	pci_power_on(pdev); */
 		
 		natsemi_reset(dev);
 		init_ring(dev);
+		spin_lock_irq(&np->lock);
 		init_registers(dev);
+		netif_device_attach(dev);
+		spin_unlock_irq(&np->lock);
 
 		np->timer.expires = jiffies + 1*HZ;
 		add_timer(&np->timer);
+	} else {
+		netif_device_attach(dev);
 	}
-	netif_device_attach(dev);
+out:
+	rtnl_unlock();
 	return 0;
 }
 
diff -urN linux-2.4.11-pre2/drivers/net/tulip/eeprom.c linux/drivers/net/tulip/eeprom.c
--- linux-2.4.11-pre2/drivers/net/tulip/eeprom.c	Wed May 16 10:25:39 2001
+++ linux/drivers/net/tulip/eeprom.c	Mon Dec  3 23:15:39 2001
@@ -148,10 +148,10 @@
 		for (i = 0; i < count; i++) {
 			unsigned char media_block = *p++;
 			int media_code = media_block & MEDIA_MASK;
-			if (media_code & 0x40)
+			if (media_block & 0x40)
 				p += 6;
 			printk(KERN_INFO "%s:  21041 media #%d, %s.\n",
-				   dev->name, media_code & 15, medianame[media_code & 15]);
+				   dev->name, media_code, medianame[media_code]);
 		}
 	} else {
 		unsigned char *p = (void *)ee_data + ee_data[27];
diff -urN linux-2.4.11-pre2/drivers/net/tulip/interrupt.c linux/drivers/net/tulip/interrupt.c
--- linux-2.4.11-pre2/drivers/net/tulip/interrupt.c	Wed Jun 20 11:15:44 2001
+++ linux/drivers/net/tulip/interrupt.c	Mon Dec  3 23:15:39 2001
@@ -301,7 +301,7 @@
 	long ioaddr = dev->base_addr;
 	int csr5;
 	int entry;
-	int missed;
+	int csr8;
 	int rx = 0;
 	int tx = 0;
 	int oi = 0;
@@ -434,7 +434,6 @@
 				}
 			}
 			if (csr5 & RxDied) {		/* Missed a Rx frame. */
-                                tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
 #ifdef CONFIG_NET_HW_FLOWCONTROL
 				if (tp->fc_bit && !test_bit(tp->fc_bit, &netdev_fc_xoff)) {
 					tp->stats.rx_errors++;
@@ -548,9 +547,8 @@
 		}
 	}
 
-	if ((missed = inl(ioaddr + CSR8) & 0x1ffff)) {
-		tp->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed;
-	}
+	csr8 = inl(ioaddr + CSR8);
+	tp->stats.rx_dropped += (csr8 & 0x1ffff) + ((csr8 >> 17) & 0xfff);
 
 	if (tulip_debug > 4)
 		printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n",
diff -urN linux-2.4.11-pre2/drivers/net/tulip/tulip_core.c linux/drivers/net/tulip/tulip_core.c
--- linux-2.4.11-pre2/drivers/net/tulip/tulip_core.c	Mon Dec  3 23:15:30 2001
+++ linux/drivers/net/tulip/tulip_core.c	Mon Dec  3 23:15:39 2001
@@ -15,8 +15,8 @@
 */
 
 #define DRV_NAME	"tulip"
-#define DRV_VERSION	"0.9.15-pre6"
-#define DRV_RELDATE	"July 2, 2001"
+#define DRV_VERSION	"0.9.15-pre7"
+#define DRV_RELDATE	"Oct 2, 2001"
 
 #include <linux/config.h>
 #include <linux/module.h>
diff -urN linux-2.4.11-pre2/drivers/net/wireless/airo.c linux/drivers/net/wireless/airo.c
--- linux-2.4.11-pre2/drivers/net/wireless/airo.c	Mon Sep 17 22:52:35 2001
+++ linux/drivers/net/wireless/airo.c	Mon Dec  3 23:15:39 2001
@@ -341,6 +341,7 @@
 
 /* The RIDs */
 #define RID_CAPABILITIES 0xFF00
+#define RID_RSSI       0xFF04
 #define RID_CONFIG     0xFF10
 #define RID_SSID       0xFF11
 #define RID_APLIST     0xFF12
@@ -627,6 +628,16 @@
   u16 atimWindow;
 } BSSListRid;
 
+typedef struct {
+  u8 rssipct;
+  u8 rssidBm;
+} tdsRssiEntry;
+
+typedef struct {
+  u16 len;
+  tdsRssiEntry x[256];
+} tdsRssiRid;
+
 #pragma pack()
 
 #define TXCTL_TXOK (1<<1) /* report if tx is ok */
@@ -774,6 +785,7 @@
 			int whichbap);
 	int (*header_parse)(struct sk_buff*, unsigned char *);
 	unsigned short *flash;
+	tdsRssiEntry *rssi;
 #ifdef WIRELESS_EXT
 	int			need_commit;	// Need to set config
 	struct iw_statistics	wstats;		// wireless stats
@@ -1076,6 +1088,8 @@
 	struct airo_info *ai = (struct airo_info*)dev->priv;
 	if (ai->flash)
 		kfree(ai->flash);
+	if (ai->rssi)
+		kfree(ai->rssi);
 	takedown_proc_entry( dev, ai );
 	if (ai->registered) {
 		unregister_netdev( dev );
@@ -1382,7 +1396,10 @@
 					if (!memcmp(sa,apriv->spy_address[i],6))
 					{
 						apriv->spy_stat[i].qual = hdr.rssi[0];
-						apriv->spy_stat[i].level = hdr.rssi[1];
+						if (apriv->rssi)
+							apriv->spy_stat[i].level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm;
+						else
+							apriv->spy_stat[i].level = (hdr.rssi[1] + 321) / 2;
 						apriv->spy_stat[i].noise = 0;
 						apriv->spy_stat[i].updated = 3;
 						break;
@@ -1568,9 +1585,29 @@
 	if ( config->len ) {
 		cfg = *config;
 	} else {
+		tdsRssiRid rssi_rid;
+	
 		// general configuration (read/modify/write)
 		status = readConfigRid(ai, &cfg);
 		if ( status != SUCCESS ) return ERROR;
+
+		status = PC4500_readrid(ai,RID_RSSI,&rssi_rid,sizeof(rssi_rid));
+		if ( status == SUCCESS ) {
+			if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL)
+				memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512);
+		}
+		else {
+			CapabilityRid cap_rid;
+			if (ai->rssi) {
+				kfree(ai->rssi);
+				ai->rssi = NULL;
+			}
+			status = readCapabilityRid(ai, &cap_rid);
+			if ((status == SUCCESS) && (cap_rid.softCap & 8))
+				cfg.rmode |= RXMODE_NORMALIZED_RSSI;
+			else
+				printk(KERN_WARNING "airo: unknown received signal level\n");
+		}
 		cfg.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS;
     
 		/* Save off the MAC */
@@ -3814,7 +3851,7 @@
 
 			/* Hum... Should put the right values there */
 			range.max_qual.qual = 10;
-			range.max_qual.level = 100;
+			range.max_qual.level = 0;
 			range.max_qual.noise = 0;
 			range.sensitivity = 65535;
 
@@ -3976,7 +4013,10 @@
 				loseSync = 0;
 				memcpy(s[i].sa_data, BSSList.bssid, 6);
 				s[i].sa_family = ARPHRD_ETHER;
-				qual[i].level = BSSList.rssi;
+				if (local->rssi)
+					qual[i].level = 0x100 - local->rssi[BSSList.rssi].rssidBm;
+				else
+					qual[i].level = (BSSList.rssi + 321) / 2;
 				qual[i].qual = qual[i].noise = 0;
 				qual[i].updated = 2;
 				if (BSSList.index == 0xffff) break;
@@ -4190,7 +4230,10 @@
 
 	/* Signal quality and co. But where is the noise level ??? */
 	local->wstats.qual.qual = status_rid.signalQuality;
-	local->wstats.qual.level = status_rid.normalizedSignalStrength;
+	if (local->rssi)
+		local->wstats.qual.level = 0x100 - local->rssi[status_rid.sigQuality].rssidBm;
+	else
+		local->wstats.qual.level = (status_rid.normalizedSignalStrength + 321) / 2;
 	local->wstats.qual.noise = 0;
 	local->wstats.qual.updated = 3;
 
diff -urN linux-2.4.11-pre2/drivers/net/wireless/hermes.c linux/drivers/net/wireless/hermes.c
--- linux-2.4.11-pre2/drivers/net/wireless/hermes.c	Mon Sep 17 22:52:35 2001
+++ linux/drivers/net/wireless/hermes.c	Mon Dec  3 23:15:39 2001
@@ -14,8 +14,31 @@
  * particular order).
  *
  * Copyright (C) 2000, David Gibson, Linuxcare Australia <hermes@gibson.dropbear.id.au>
+ * Copyright (C) 2001, David Gibson, IBM <hermes@gibson.dropbear.id.au>
  * 
- * This file distributed under the GPL, version 2.  */
+ * 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.
+ */
+
+#include <linux/config.h>
 
 #include <linux/module.h>
 #include <linux/types.h>
@@ -30,10 +53,10 @@
 
 #include "hermes.h"
 
-static char version[] __initdata = "hermes.c: 1 Aug 2001 David Gibson <hermes@gibson.dropbear.id.au>";
+static char version[] __initdata = "hermes.c: 3 Oct 2001 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>");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("Dual MPL/GPL");
 
 /* These are maximum timeouts. Most often, card wil react much faster */
 #define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */
@@ -42,9 +65,6 @@
 #define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */
 #define BAP_BUSY_TIMEOUT (500) /* In iterations of ~1us */
 
-#define MAX(a, b) ( (a) > (b) ? (a) : (b) )
-#define MIN(a, b) ( (a) < (b) ? (a) : (b) )
-
 /*
  * Debugging helpers
  */
@@ -292,7 +312,7 @@
  * from firmware
  *
  * Callable from any context */
-static int hermes_bap_seek(hermes_t *hw, int bap, uint16_t id, uint16_t offset)
+int hermes_bap_seek(hermes_t *hw, int bap, uint16_t id, uint16_t offset)
 {
 	int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0;
 	int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0;
@@ -305,9 +325,14 @@
 
 	k = BAP_BUSY_TIMEOUT;
 	reg = hermes_read_reg(hw, oreg);
+	while ((reg & HERMES_OFFSET_BUSY) & k) {
+		k--;
+		udelay(1);
+		reg = hermes_read_reg(hw, oreg);
+	}
 
 	if (reg & HERMES_OFFSET_BUSY)
-		return -EBUSY;
+		return -ETIMEDOUT;
 
 	/* Now we actually set up the transfer */
 	hermes_write_reg(hw, sreg, id);
@@ -342,7 +367,7 @@
  *
  * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
  */
-int hermes_bap_pread(hermes_t *hw, int bap, void *buf, uint16_t len,
+int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len,
 		     uint16_t id, uint16_t offset)
 {
 	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
@@ -356,7 +381,7 @@
 		goto out;
 
 	/* Actually do the transfer */
-	hermes_read_data(hw, dreg, buf, len/2);
+	hermes_read_words(hw, dreg, buf, len/2);
 
  out:
 	return err;
@@ -368,7 +393,7 @@
  *
  * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
  */
-int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, uint16_t len,
+int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
 		      uint16_t id, uint16_t offset)
 {
 	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
@@ -382,7 +407,7 @@
 		goto out;
 	
 	/* Actually do the transfer */
-	hermes_write_data(hw, dreg, buf, len/2);
+	hermes_write_words(hw, dreg, buf, len/2);
 
  out:	
 	return err;
@@ -434,17 +459,7 @@
 	   lengths in the records seem to be wrong, frequently */
 	count = buflen / 2;
 
-#if 0
-	if (length)
-		count = (MIN(buflen, rlength) + 1) / 2;
-	else {
-		count = buflen / 2;
-		if (rlength != buflen)
-			printk(KERN_WARNING "hermes_read_ltv(): Incorrect \
-record length %d instead of %d on RID 0x%04x\n", rlength, buflen, rid);
-	}
-#endif
-	hermes_read_data(hw, dreg, buf, count);
+	hermes_read_words(hw, dreg, buf, count);
 
  out:
 	return err;
@@ -470,7 +485,7 @@
 
 	count = length - 1;
 
-	hermes_write_data(hw, dreg, value, count);
+	hermes_write_words(hw, dreg, value, count);
 
 	err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, 
 				rid, &resp);
diff -urN linux-2.4.11-pre2/drivers/net/wireless/hermes.h linux/drivers/net/wireless/hermes.h
--- linux-2.4.11-pre2/drivers/net/wireless/hermes.h	Mon Sep 17 22:52:35 2001
+++ linux/drivers/net/wireless/hermes.h	Mon Dec  3 23:15:39 2001
@@ -50,6 +50,7 @@
 #define		HERMES_FRAME_LEN_MAX		(2304)
 #define		HERMES_MAX_MULTICAST		(16)
 #define		HERMES_MAGIC			(0x7d1f)
+#define		HERMES_SYMBOL_MAX_VER		(14)
 
 /*
  * Hermes register offsets
@@ -202,24 +203,21 @@
 #define		HERMES_RID_WEP_AVAIL		(0xfd4f)
 #define		HERMES_RID_CURRENT_CHANNEL	(0xfdc1)
 #define		HERMES_RID_DATARATES		(0xfdc6)
-#define		HERMES_RID_SYMBOL_PRIMARY_VER	(0xfd03)
-#define		HERMES_RID_SYMBOL_SECONDARY_VER	(0xfd21)
+#define		HERMES_RID_SYMBOL_SECONDARY_VER	(0xfd24)
 #define		HERMES_RID_SYMBOL_KEY_LENGTH	(0xfc2B)
 
 /*
  * Frame structures and constants
  */
 
-#define __PACKED__ __attribute__ ((packed))
-
 typedef struct hermes_frame_desc {
 	/* Hermes - i.e. little-endian byte-order */
-	uint16_t status __PACKED__;
-	uint16_t res1, res2 __PACKED__;
-	uint16_t q_info __PACKED__;
-	uint16_t res3, res4 __PACKED__;
-	uint16_t tx_ctl __PACKED__;
-} hermes_frame_desc_t;
+	uint16_t status;
+	uint16_t res1, res2;
+	uint16_t q_info;
+	uint16_t res3, res4;
+	uint16_t tx_ctl;
+} __attribute__ ((packed)) hermes_frame_desc_t;
 
 #define		HERMES_RXSTAT_ERR		(0x0003)
 #define		HERMES_RXSTAT_MACPORT		(0x0700)
@@ -265,20 +263,16 @@
 #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)))
 
-/* Note that for the next two, the count is in 16-bit words, not bytes */
-#define hermes_read_data(hw, off, buf, count) (insw((hw)->iobase + (off), (buf), (count)))
-#define hermes_write_data(hw, off, buf, count) (outsw((hw)->iobase + (off), (buf), (count)))
-
 /* Function prototypes */
 void hermes_struct_init(hermes_t *hw, uint io);
 int hermes_reset(hermes_t *hw);
 int hermes_docmd_wait(hermes_t *hw, uint16_t cmd, uint16_t parm0, hermes_response_t *resp);
 int hermes_allocate(hermes_t *hw, uint16_t size, uint16_t *fid);
 
-
-int hermes_bap_pread(hermes_t *hw, int bap, void *buf, uint16_t len,
+int hermes_bap_seek(hermes_t *hw, int bap, uint16_t id, uint16_t offset);
+int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len,
 		       uint16_t id, uint16_t offset);
-int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, uint16_t len,
+int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
 			uint16_t id, uint16_t offset);
 int hermes_read_ltv(hermes_t *hw, int bap, uint16_t rid, int buflen,
 		    uint16_t *length, void *buf);
@@ -322,6 +316,10 @@
 
 #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)))
 
 #define HERMES_READ_RECORD(hw, bap, rid, buf) \
 	(hermes_read_ltv((hw),(bap),(rid), sizeof(*buf), NULL, (buf)))
diff -urN linux-2.4.11-pre2/drivers/net/wireless/orinoco.c linux/drivers/net/wireless/orinoco.c
--- linux-2.4.11-pre2/drivers/net/wireless/orinoco.c	Mon Sep 17 22:52:35 2001
+++ linux/drivers/net/wireless/orinoco.c	Mon Dec  3 23:15:39 2001
@@ -1,4 +1,4 @@
-/* orinoco.c 0.07	- (formerly known as dldwd_cs.c and orinoco_cs.c)
+/* orinoco.c 0.08	- (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/
@@ -190,13 +190,35 @@
  *	  Rx path, but don't make as much noise about it.
  *	o Firmware detection cleanups.
  *
+ * v0.07 -> v0.08 - 3/10/2001 - David Gibson
+ *	o Fixed a possible buffer overrun found by the Stanford checker (in
+ *	  dldwd_ioctl_setiwencode()).  Can only be called by root anyway, so not
+ *	  a big problem.
+ *	o Turned has_big_wep on for Intersil cards.  That's not true for all of them
+ *	  but we should at least let the capable ones try.
+ *	o Wait for BUSY to clear at the beginning of hermes_bap_seek().  I
+ *	  realised that my assumption that the driver's serialization
+ *	  would prevent the BAP being busy on entry was possibly false, because
+ *	  things other than seeks may make the BAP busy.
+ *	o Use "alternate" (oui 00:00:00) encapsulation by default.
+ *	  Setting use_old_encaps will mimic the old behaviour, but I
+ *	  think we will be able to eliminate this.
+ *	o Don't try to make __initdata const (the version string).
+ *	  This can't work because of the way the __initdata sectioning
+ *	   works.
+ *	o Added MODULE_LICENSE tags.
+ *	o Support for PLX (transparent PCMCIA->PCI brdge) cards.
+ *	o Improved support for Symbol firmware - we can actually tell
+ *	   the version now.
  *
  * TODO - Jean II
- *	o inline functions (lot's of candidate, need to reorder code)
+ *	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)
  */
 
+#include <linux/config.h>
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -227,7 +249,7 @@
 #include "hermes.h"
 #include "orinoco.h"
 
-static char version[] __initdata = "orinoco.c 0.07 (David Gibson <hermes@gibson.dropbear.id.au> and others)";
+static char version[] __initdata = "orinoco.c 0.08 (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");
 MODULE_LICENSE("Dual MPL/GPL");
@@ -238,10 +260,8 @@
 MODULE_PARM(dldwd_debug, "i");
 #endif
 
-/* FIXME: We need a better way of handling this */
-/* Set this flag to use 00:00:00 for the encapsulation oui instead of 00:00:F8 */
-static int use_alternate_encaps; /* =0 */
-MODULE_PARM(use_alternate_encaps, "i");
+int use_old_encaps = 0;
+MODULE_PARM(use_old_encaps, "i");
 
 const long channel_frequency[] = {
 	2412, 2417, 2422, 2427, 2432, 2437, 2442,
@@ -307,12 +327,13 @@
 
 /* 802.2 LLL header SNAP used for SNAP encapsulation over 802.11 */
 struct p8022_hdr encaps_hdr = {
-	0xaa, 0xaa, 0x03, {0x00, 0x00, 0xf8}
-};
-struct p8022_hdr alternate_encaps_hdr = {
 	0xaa, 0xaa, 0x03, {0x00, 0x00, 0x00}
 };
 
+struct p8022_hdr old_encaps_hdr = {
+	0xaa, 0xaa, 0x03, {0x00, 0x00, 0xf8}
+};
+
 /* How many times to retry if we get an EIO reading the BAP in the Rx path */
 #define RX_EIO_RETRY		10
 
@@ -881,7 +902,7 @@
 	
 	num = le16_to_cpu(list.len);
 	*numrates = num;
-	num = MIN(num, max);
+	num = min(num, max);
 
 	for (i = 0; i < num; i++) {
 		rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */
@@ -1286,7 +1307,7 @@
 
 	if (sta_id.vendor == 1) {
 		/* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout,
-		   ELSE, Meloc, HP, IBM, Dell 1150 */
+		   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);
@@ -1303,7 +1324,7 @@
 		priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell
 					  Gold cards from the others? */
 		priv->has_mwo = (firmver >= 0x60000);
-		priv->has_pm = (firmver >= 0x40020);
+		priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
 		priv->has_preamble = 0;
 		priv->ibss_port = 1;
 		/* Tested with Lucent firmware :
@@ -1314,27 +1335,59 @@
 		/* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */
 		/* Intel MAC : 00:02:B3:* */
 		/* 3Com MAC : 00:50:DA:* */
+		union symbol_sta_id {
+			char raw[HERMES_SYMBOL_MAX_VER];
+			char string[HERMES_SYMBOL_MAX_VER + 1];
+		} symbol_sta_id;
+
+		/* Get the Symbol firmware version */
+		err = HERMES_READ_RECORD(hw, USER_BAP,
+					 HERMES_RID_SYMBOL_SECONDARY_VER,
+					 &(symbol_sta_id.raw));
+		if (err) {
+			printk(KERN_WARNING "%s: Error %d reading Symbol firmware info. Wildly guessing capabilities...\n",
+			       dev->name, err);
+			firmver = 0;
+			symbol_sta_id.string[0] = '\0';
+		} else {
+			/* The firmware revision is a string, the format is
+			 * something like : "V2.20-01".
+			 * Quick and dirty parsing... - Jean II
+			 */
+			firmver = ((symbol_sta_id.raw[1] - '0') << 16)
+			  | ((symbol_sta_id.raw[3] - '0') << 12)
+			  | ((symbol_sta_id.raw[4] - '0') << 8)
+			  | ((symbol_sta_id.raw[6] - '0') << 4)
+			  | (symbol_sta_id.raw[7] - '0');
+
+			symbol_sta_id.string[HERMES_SYMBOL_MAX_VER] = '\0';
+		}
+
 		printk(KERN_DEBUG "%s: Looks like a Symbol firmware "
-		       "(unknown version)\n", dev->name);
+		       "version [%s] (parsing to %X)\n", dev->name,
+		       symbol_sta_id.string, firmver);
 
-		/* FIXME : we need to get Symbol firmware revision.
-		 * I tried to use SYMBOL_***ARY_VER, but it didn't
-		 * returned anything proper... */
 		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 = 1; /* FIXME */
-		priv->has_wep = 1; /* FIXME */
-		priv->has_big_wep = 1;	/* RID_SYMBOL_KEY_LENGTH */
+		priv->has_ibss = (firmver >= 0x20000);
+		priv->has_wep = (firmver >= 0x15012);
+		priv->has_big_wep = (firmver >= 0x20000);
 		priv->has_mwo = 0;
-		priv->has_pm = 1; /* FIXME */
-		priv->has_preamble = 0; /* FIXME */
+		priv->has_pm = (firmver >= 0x20000) && (firmver < 0x22000);
+		priv->has_preamble = (firmver >= 0x20000);
 		priv->ibss_port = 4;
-		/* Tested with Intel firmware : v15 => Jean II */
+		/* Tested with Intel firmware : 0x20015 => Jean II */
+		/* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
 	} else {
+		/* D-Link, Linksys, Adtron, ZoomAir, and many others...
+		 * Samsung, Compaq 100/200 and Proxim are slightly
+		 * different and less well tested */
+		/* D-Link MAC : 00:40:05:* */
+		/* Addtron MAC : 00:90:D1:* */
 		printk(KERN_DEBUG "%s: Looks like an Intersil firmware "
 		       "version %d.%02d\n", dev->name,
 		       sta_id.major, sta_id.minor);
@@ -1347,7 +1400,7 @@
 		priv->has_port3 = 1;
 		priv->has_ibss = (firmver >= 0x00007); /* FIXME */
 		priv->has_wep = (firmver >= 0x00008);
-		priv->has_big_wep = 0;
+		priv->has_big_wep = priv->has_wep;
 		priv->has_mwo = 0;
 		priv->has_pm = (firmver >= 0x00007);
 		priv->has_preamble = 0;
@@ -1427,9 +1480,9 @@
 		goto out;
 	}
 	if ( nickbuf.len )
-		len = MIN(IW_ESSID_MAX_SIZE, le16_to_cpu(nickbuf.len));
+		len = min(IW_ESSID_MAX_SIZE, le16_to_cpu(nickbuf.len));
 	else
-		len = MIN(IW_ESSID_MAX_SIZE, 2 * reclen);
+		len = min(IW_ESSID_MAX_SIZE, 2 * reclen);
 	memcpy(priv->nick, &nickbuf.val, len);
 	priv->nick[len] = '\0';
 
@@ -1556,20 +1609,12 @@
 		err = HERMES_READ_RECORD(hw, USER_BAP,
 					 HERMES_RID_COMMSQUALITY, &cq);
 		
-		le16_to_cpus(&cq.qual);
-		le16_to_cpus(&cq.signal);
-		le16_to_cpus(&cq.noise);
-		
 		DEBUG(3, "%s: Global stats = %X-%X-%X\n", dev->name,
 		      cq.qual, cq.signal, cq.noise);
 
-		/* Why are we using MIN/MAX ? We don't really care
-		 * if the value goes above max, because we export the
-		 * raw dBm values anyway. The normalisation should be done
-		 * in user space - Jean II */
-		wstats->qual.qual = MAX(MIN(cq.qual, 0x8b-0x2f), 0);
-		wstats->qual.level = MAX(MIN(cq.signal, 0x8a), 0x2f) - 0x95;
-		wstats->qual.noise = MAX(MIN(cq.noise, 0x8a), 0x2f) - 0x95;
+		wstats->qual.qual = le16_to_cpu(cq.qual);
+		wstats->qual.level = le16_to_cpu(cq.signal);
+		wstats->qual.noise = le16_to_cpu(cq.noise);
 		wstats->qual.updated = 7;
 	}
 
@@ -1593,9 +1638,9 @@
 	 * source address with out list, and if match, get the stats... */
 	for (i = 0; i < priv->spy_number; i++)
 		if (!memcmp(mac, priv->spy_address[i], ETH_ALEN)) {
-			priv->spy_stat[i].qual = MAX(MIN(cq->qual, 0x8b-0x2f), 0);
-			priv->spy_stat[i].level = MAX(MIN(cq->signal, 0x8a), 0x2f) - 0x95;
-			priv->spy_stat[i].noise = MAX(MIN(cq->noise, 0x8a), 0x2f) - 0x95;
+			priv->spy_stat[i].qual = cq->qual;
+			priv->spy_stat[i].level = cq->signal;
+			priv->spy_stat[i].noise = cq->noise;
 			priv->spy_stat[i].updated = 7;
 		}
 }
@@ -1674,7 +1719,7 @@
 	dldwd_lock(priv);
 
 	/* Length of the packet body */
-	len = MAX(skb->len - ETH_HLEN, ETH_ZLEN);
+	len = max_t(int,skb->len - ETH_HLEN, ETH_ZLEN);
 
 	eh = (struct ethhdr *)skb->data;
 
@@ -1699,12 +1744,13 @@
 		hdr.p8023.h_proto = htons(data_len + ENCAPS_OVERHEAD);
 		
 		/* 802.2 header */
-		/* FIXME: ugh, what a hack for the 00:00:00 APs.  Need to find a better way */
-		if (use_alternate_encaps)
-			memcpy(&hdr.p8022, &alternate_encaps_hdr, sizeof(alternate_encaps_hdr));
+		if (! use_old_encaps) 
+			memcpy(&hdr.p8022, &encaps_hdr,
+			       sizeof(encaps_hdr));
 		else
-			memcpy(&hdr.p8022, &encaps_hdr, sizeof(encaps_hdr));
-
+			memcpy(&hdr.p8022, &encaps_hdr,
+			       sizeof(old_encaps_hdr));
+			
 		hdr.ethertype = eh->h_proto;
 		err  = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr),
 					 txfid, 0);
@@ -1933,12 +1979,12 @@
 	uint16_t xlen = 0;
 	int err = 0;
 	char keybuf[MAX_KEY_SIZE];
-
+	
 	if (erq->pointer) {
 		/* We actually have a key to set */
-		if(erq->length > MAX_KEY_SIZE)
+		if ( (erq->length < SMALL_KEY_SIZE) || (erq->length > MAX_KEY_SIZE) )
 			return -EINVAL;
-
+		
 		if (copy_from_user(keybuf, erq->pointer, erq->length))
 			return -EFAULT;
 	}
@@ -3512,7 +3558,7 @@
 
 		buf += sprintf(buf, "%-15s (0x%04x): length=%d (%d bytes)\tvalue=", record_table[i].name,
 			       rid, length, (length-1)*2);
-		len = MIN( MAX(minlen, (length-1)*2), maxlen);
+		len = min( (int)max(minlen, ((int)length-1)*2), maxlen);
 
 		switch (record_table[i].displaytype) {
 		case DISPLAY_WORDS:
@@ -3531,7 +3577,7 @@
 			break;
 
 		case DISPLAY_STRING:
-			len = MIN(len, le16_to_cpu(val16[0])+2);
+			len = min(len, le16_to_cpu(val16[0])+2);
 			val8[len] = '\0';
 			buf += sprintf(buf, "\"%s\"", (char *)&val16[1]);
 			break;
diff -urN linux-2.4.11-pre2/drivers/net/wireless/orinoco.h linux/drivers/net/wireless/orinoco.h
--- linux-2.4.11-pre2/drivers/net/wireless/orinoco.h	Mon Sep 17 22:52:35 2001
+++ linux/drivers/net/wireless/orinoco.h	Mon Dec  3 23:15:39 2001
@@ -25,7 +25,7 @@
 #define DLDWD_MACPORT		0
 #define IRQ_LOOP_MAX		10
 #define TX_NICBUF_SIZE		2048
-#define TX_NICBUF_SIZE_BUG	1585		/* Bug in Intel firmware */
+#define TX_NICBUF_SIZE_BUG	1585		/* Bug in Symbol firmware */
 #define MAX_KEYS		4
 #define MAX_KEY_SIZE		14
 #define LARGE_KEY_SIZE		13
@@ -110,7 +110,7 @@
 
 #ifdef ORINOCO_DEBUG
 extern int dldwd_debug;
-#define DEBUG(n, args...) if (dldwd_debug>(n)) printk(KERN_DEBUG args)
+#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)
 #else
 #define DEBUG(n, args...) do { } while (0)
@@ -119,9 +119,6 @@
 
 #define TRACE_ENTER(devname) DEBUG(2, "%s: -> " __FUNCTION__ "()\n", devname);
 #define TRACE_EXIT(devname)  DEBUG(2, "%s: <- " __FUNCTION__ "()\n", devname);
-
-#define MAX(a, b) ( (a) > (b) ? (a) : (b) )
-#define MIN(a, b) ( (a) < (b) ? (a) : (b) )
 
 #define RUP_EVEN(a) ( (a) % 2 ? (a) + 1 : (a) )
 
diff -urN linux-2.4.11-pre2/drivers/net/wireless/orinoco_cs.c linux/drivers/net/wireless/orinoco_cs.c
--- linux-2.4.11-pre2/drivers/net/wireless/orinoco_cs.c	Mon Sep 17 22:52:35 2001
+++ linux/drivers/net/wireless/orinoco_cs.c	Mon Dec  3 23:15:39 2001
@@ -1,4 +1,4 @@
-/* orinoco_cs.c 0.07	- (formerly known as dldwd_cs.c)
+/* orinoco_cs.c 0.08	- (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/
@@ -10,6 +10,8 @@
  * Copyright notice & release notes in file orinoco.c
  */
 
+#include <linux/config.h>
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -42,7 +44,7 @@
 
 /*====================================================================*/
 
-static char version[] __initdata = "orinoco_cs.c 0.07 (David Gibson <hermes@gibson.dropbear.id.au> and others)";
+static char version[] __initdata = "orinoco_cs.c 0.08 (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");
diff -urN linux-2.4.11-pre2/drivers/pci/pci.ids linux/drivers/pci/pci.ids
--- linux-2.4.11-pre2/drivers/pci/pci.ids	Fri Sep  7 09:28:38 2001
+++ linux/drivers/pci/pci.ids	Mon Dec  3 23:15:39 2001
@@ -27,6 +27,8 @@
 0e11  Compaq Computer Corporation
 	0001  PCI to EISA Bridge
 	0002  PCI to ISA Bridge
+	0049  NC7132 Gigabit Upgrade Module
+	004a  NC6136 Gigabit Server Adapter
 	0508  Netelligent 4/16 Token Ring
 	1000  Triflex/Pentium Bridge, Model 1000
 	2000  Triflex/Pentium Bridge, Model 2000
@@ -40,6 +42,8 @@
 	a0f0  Advanced System Management Controller
 	a0f3  Triflex PCI to ISA Bridge
 	a0f7  PCI Hotplug Controller
+		8086 002a  PCI Hotplug Controller A
+		8086 002b  PCI Hotplug Controller B
 	a0f8  USB Open Host Controller
 	ae10  Smart-2/P RAID Controller
 		0e11 4030  Smart-2/P Array Controller
@@ -61,13 +65,29 @@
 	ae6d  NorthStar CPU to PCI Bridge
 	b011  Integrated Netelligent 10/100
 	b012  Netelligent 10 T/2
+	b01e  NC3120 Fast Ethernet NIC
+	b01f  NC3122 Fast Ethernet NIC
+	b02f  NC1120 Ethernet NIC
 	b030  Netelligent WS 5100
-	b04a  10/100TX WOL UTP Controller
-	b0c6  10/100TX Embedded WOL UTP Controller
-	b0d7  NC3121 (Rev A & B)
+	b04a  10/100 TX PCI Intel WOL UTP Controller
+	b0c6  NC3161 Fast Ethernet NIC
+	b0c7  NC3160 Fast Ethernet NIC
+	b0d7  NC3121 Fast Ethernet NIC
+	b0dd  NC3131 Fast Ethernet NIC
+	b0de  NC3132 Fast Ethernet Module
+	b0df  NC6132 Gigabit Module
+	b0e0  NC6133 Gigabit Module
+	b0e1  NC3133 Fast Ethernet Module
+	b123  NC6134 Gigabit NIC
+	b134  NC3163 Fast Ethernet NIC
+	b13c  NC3162 Fast Ethernet NIC
+	b144  NC3123 Fast Ethernet NIC
+	b163  NC3134 Fast Ethernet NIC
+	b164  NC3135 Fast Ethernet Upgrade Module
+	b1a4  NC7131 Gigabit Server Adapter
 	f130  NetFlex-3/P ThunderLAN 1.0
 	f150  NetFlex-3/P ThunderLAN 2.3
-1000  Symbios Logic Inc. (formerly NCR)
+1000  LSI Logic / Symbios Logic (formerly NCR)
 	0001  53c810
 		1000 1000  8100S
 	0002  53c820
@@ -141,16 +161,19 @@
 		0e11 b10e  3D Rage LT Pro (Compaq Armada 1750)
 		1028 0085  Rage 3D LT Pro
 	4c44  3D Rage LT Pro AGP-66
-	4c46  Mobility M3 AGP 2x
+	4c45  Rage Mobility M3 AGP
+	4c46  Rage Mobility M3 AGP 2x
 	4c47  3D Rage LT-G 215LG
 	4c49  3D Rage LT Pro
-	4c4d  3D Rage P/M Mobility AGP 2x
-	4c4e  3D Rage L Mobility AGP 2x
+	4c4d  Rage Mobility P/M AGP 2x
+	4c4e  Rage Mobility L AGP 2x
 	4c50  3D Rage LT Pro
 	4c51  3D Rage LT Pro
-	4c52  3D Rage P/M Mobility
-	4c53  3D Rage L Mobility
+	4c52  Rage Mobility P/M
+	4c53  Rage Mobility L
 	4c54  264LT [Mach64 LT]
+	4d46  Rage Mobility M4 AGP
+	4d4c  Rage Mobility M4 AGP
 	5041  Rage 128 PA
 	5042  Rage 128 PB
 	5043  Rage 128 PC
@@ -244,7 +267,7 @@
 	000f  OHCI Compliant FireWire Controller
 	0011  National PCI System I/O
 	0012  USB Controller
-	0020  DP83815 (MacPhyter) Ethernet Controller
+	0020  DP83815
 	d001  87410 IDE
 100c  Tseng Labs Inc
 	3202  ET4000/W32p rev A
@@ -276,6 +299,8 @@
 		1113 1207  EN-1207-TX Fast Ethernet
 		1186 1100  DFE-500TX Fast Ethernet
 		1186 1112  DFE-570TX Fast Ethernet
+		1186 1140  DFE-660 Cardbus Ethernet 10/100
+		1186 1142  DFE-660 Cardbus Ethernet 10/100
 		1282 9100  AEF-380TXD Fast Ethernet
 		1385 1100  FA310TX Fast Ethernet
 		2646 0001  KNE100TX Fast Ethernet
@@ -374,7 +399,7 @@
 	0020  MCA
 	0022  IBM27-82351
 	002d  Python
-	002e  ServeRAID controller
+	002e  ServeRAID-3x
 	0036  Miami
 	003a  CPU to PCI Bridge
 	003e  16/4 Token ring UTP/STP controller
@@ -415,6 +440,10 @@
 	0144  Yotta Video Compositor Output
 		1014 0145 Yotta Output Controller (ytout)
 	0156  405GP PLB to PCI Bridge
+	01bd  Netfinity ServeRAID controller
+	01be  ServeRAID-4M
+	01bf  ServeRAID-4L
+	022e  ServeRAID-4H
 	ffff  MPIC-2 interrupt controller
 1015  LSI Logic Corp of Canada
 1016  ICL Personal Systems
@@ -438,6 +467,9 @@
 	9712  Pipeline 9712
 	c24a  90C
 101e  American Megatrends Inc.
+	1960  MegaRAID
+		1028 0471 PowerEdge RAID Controller 3/QC
+		1028 0493 PowerEdge RAID Controller 3/DC
 	9010  MegaRAID
 	9030  EIDE Controller
 	9031  EIDE Controller
@@ -589,6 +621,7 @@
 	0005  PowerEdge Expandable RAID Controller 3/Di
 	0006  PowerEdge Expandable RAID Controller 3/Di
 	0008  PowerEdge Expandable RAID Controller 3/Di
+	000a  PowerEdge Expandable RAID Controller 3/Di
 1029  Siemens Nixdorf IS
 102a  LSI Logic
 	0000  HYDRA
@@ -642,6 +675,8 @@
 		0e11 b16f  Matrox MGA-G400 AGP
 		102b 0328  Millennium G400 16Mb SDRAM
 		102b 0338  Millennium G400 16Mb SDRAM
+		102b 0378  Millennium G400 32Mb SDRAM
+		102b 0641  Millennium G450 32Mb SDRAM
 		102b 19d8  Millennium G400 16Mb SGRAM
 		102b 19f8  Millennium G400 32Mb SGRAM
 		102b 2159  Millennium G400 Dual Head 16Mb
@@ -664,6 +699,8 @@
 		102b ff05  MGA-G100 Productiva AGP Multi-Monitor
 		110a 001e  MGA-G100 AGP
 	2007  MGA Mistral
+	2527  MGA G550 AGP
+		102b 0f84  Millennium G550 Dual Head DDR 32Mb
 	4536  VIA Framegrabber
 	6573  Shark 10/100 Multiport SwitchNIC
 102c  Chips and Technologies
@@ -984,6 +1021,7 @@
 	4802  Falcon
 	4803  Hawk
 	4806  CPX8216
+	4d68  20268
 	5600  SM56 PCI Modem
 		1057 0300  SM56 PCI Speakerphone Modem
 		1057 0301  SM56 PCI Voice Modem
@@ -1129,19 +1167,26 @@
 	0012  YMF-754 [DS-1E Audio Controller]
 		1073 0012  DS-XG PCI Audio Codec
 	0020  DS-1 Audio
+	2000  DS2416 Digital Mixing Card
+		1073 2000  DS2416 Digital Mixing Card
 1074  NexGen Microsystems
 	4e78  82c500/1
 1075  Advanced Integrations Research
 1076  Chaintech Computer Co. Ltd
-1077  Q Logic
+1077  QLogic Corp.
+	1016  QLA10160
 	1020  ISP1020
 	1022  ISP1022
-	1080  ISP1080
-	1240  ISP1240
-	1280  ISP1280
+	1080  QLA1080
+	1216  QLA12160
+		101e 8471 QLA12160 on AMI MegaRAID
+		101e 8493 QLA12160 on AMI MegaRAID
+	1240  QLA1240
+	1280  QLA1280
 	2020  ISP2020A
-	2100  ISP2100
-	2200  ISP2200
+	2100  QLA2100
+	2200  QLA2200
+	2300  QLA2300
 1078  Cyrix Corporation
 	0000  5510 [Grappa]
 	0001  PCI Master
@@ -1291,7 +1336,7 @@
 109e  Brooktree Corporation
 	0350  Bt848 TV with DMA push
 	0351  Bt849A Video capture
-	036c  Bt879(?) Video Capture
+	036c  Bt879(??) Video Capture
 		13e9 0070  Win/TV (Video Section)
 	036e  Bt878
 		0070 13eb  WinTV/GO
@@ -1476,6 +1521,8 @@
 	906e  9060ES
 	9080  9080
 		10b5 9080  9080 [real subsystem ID not set]
+	a001  GTEK Jetport II 2 port serial adaptor
+	c001  GTEK Cyclone 16/32 port serial adaptor
 10b6  Madge Networks
 	0001  Smart 16/4 PCI Ringnode
 	0002  Smart 16/4 PCI Ringnode Mk2
@@ -1505,13 +1552,13 @@
 		10b7 3590  TokenLink Velocity XL Adapter
 	4500  3c450 Cyclone/unknown
 	5055  3c555 Laptop Hurricane
-	6055  3c556 Laptop Tornado
+	6055  3c556 Laptop Hurricane
 	6056  3c556B Laptop Hurricane
 	5057  3c575 [Megahertz] 10/100 LAN CardBus
 		10b7 5a57  3C575 Megahertz 10/100 LAN Cardbus PC Card
-	5157  3CCFE575BT Cyclone CardBus
+	5157  3c575 [Megahertz] 10/100 LAN CardBus
 		10b7 5b57  3C575 Megahertz 10/100 LAN Cardbus PC Card
-	5257  3CCFE575CT Tornado CardBus
+	5257  3CCFE575CT Cyclone CardBus
 	5900  3c590 10BaseT [Vortex]
 	5920  3c592 EISA 10mbps Demon/Vortex
 	5950  3c595 100BaseTX [Vortex]
@@ -1521,8 +1568,8 @@
 	5b57  3c595 [Megahertz] 10/100 LAN CardBus
 		10b7 5b57  3C575 Megahertz 10/100 LAN Cardbus PC Card
 	6560  3CCFE656 Cyclone CardBus
-	6562  3CCFEM656B Cyclone CardBus
-	6564  3CXFEM656C Tornado CardBus
+	6562  3CCFEM656 [id 6562] Cyclone CardBus
+	6564  3CCFEM656 [id 6564] Cyclone CardBus
 	7646  3cSOHO100-TX Hurricane
 	8811  Token ring
 	9000  3c900 10BaseT [Boomerang]
@@ -1564,8 +1611,8 @@
 		10b7 1000  3C905C-TX Fast Etherlink for PC Management NIC
 	9800  3c980-TX [Fast Etherlink XL Server Adapter]
 		10b7 9800  3c980-TX Fast Etherlink XL Server Adapter
-	9805  3c982 Dual Port Server Cyclone
-		10b7 9805  3c982 Dual Port Server Cyclone
+	9805  3c980-TX 10/100baseTX NIC [Python-T]
+		10b7 9805  3c980 10/100baseTX NIC [Python-T]
 10b8  Standard Microsystems Corp [SMC]
 	0005  83C170QF
 		1055 e000  LANEPIC
@@ -1674,6 +1721,8 @@
 		10f7 8312  MagicGraph 128XD
 	0005  [MagicMedia 256AV]
 	0006  NM2360 [MagicMedia 256ZX]
+	0016  NM2380 [MagicMedia 256XL+]
+		10c8 0016  MagicMedia 256XL+
 	0083  [MagicGraph 128ZV Plus]
 	8005  [MagicMedia 256AV Audio]
 		0e11 b0d1  MagicMedia 256AV Audio Device on Discovery
@@ -1730,7 +1779,7 @@
 	0008  EDGE 3D [NV1]
 	0009  EDGE 3D [NV1]
 	0010  Mutara V08 [NV2]
-	0020  Riva TnT 128 [NV04]
+	0020  Riva TnT [NV04]
 		1043 0200  V3400 TNT
 		1048 0c18  Erazor II SGRAM
 		1092 0550  Viper V550
@@ -1803,14 +1852,16 @@
 		1102 102e  CT6971 GeForce 256 DDR
 		14af 5021  3D Prophet DDR-DVI
 	0103  Quadro (GeForce 256 GL)
-	0110  NV11
-	0111  NV11 DDR
-	0113  NV11 GL
-	0150  NV15 (Geforce2 GTS)
+	0110  NV11 (GeForce2 MX)
+	0111  NV11 (GeForce2 MX DDR)
+	0112  GeForce2 Go
+	0113  NV11 (GeForce2 MXR)
+	0150  NV15 (Geforce2 Pro)
 		107d 2840  WinFast GeForce2 GTS with TV output
 	0151  NV15 DDR (Geforce2 GTS)
-	0152  NV15 Bladerunner (Geforce2 GTS)
-	0153  NV15 GL (Quadro2)
+	0152  NV15 Bladerunner (Geforce2 Ultra)
+	0153  NV15 GL (Quadro2 Pro)
+	0203  Quadro DCC
 10df  Emulex Corporation
 	10df  Light Pulse Fibre Channel Adapter
 	1ae5  LP6000 Fibre Channel Host Adapter
@@ -1824,6 +1875,7 @@
 	9128  IMS9129 [Twin turbo 128]
 10e1  Tekram Technology Co.,Ltd.
 	0391  TRM-S1040
+		10e1 0391  DC-315U SCSI-3 Host Adapter
 	690c  DC-690c
 	dc29  DC-290
 10e2  Aptix Corporation
@@ -1877,6 +1929,7 @@
 		1025 8921  ALN-325
 		10bd 0320  EP-320X-R
 		10ec 8139  RT8139
+		1186 1300  DFE-538TX
 		1186 1320  SN5200
 		1259 2500  AT-2500TX
 		1429 d010  ND010
@@ -1926,7 +1979,7 @@
 	9401  INI-950
 	9500  360P
 1102  Creative Labs
-	0002  SB Live! EMU10000
+	0002  SB Live! EMU10k1
 		1102 0020  CT4850 SBLive! Value
 		1102 0021  CT4620 SBLive!
 		1102 002f  SBLive! mainboard implementation 
@@ -1942,9 +1995,10 @@
 		1102 8051  CT4850 SBLive! Value
 	7002  SB Live!
 		1102 0020  Gameport Joystick
-1103  HighPoint Technologies, Inc.
-	0003  HPT343 UltraDMA 33 IDE Controller
-	0004  HPT366/370 UltraDMA 66/100 IDE Controller
+1103  Triones Technologies, Inc.
+	0003  HPT343
+	0004  HPT366 / HPT370
+		1103 0005  HPT370 UDMA100
 1104  RasterOps Corp.
 1105  Sigma Designs, Inc.
 	8300  REALmagic Hollywood Plus DVD Decoder
@@ -1955,7 +2009,7 @@
 	0505  VT82C505
 	0561  VT82C561
 	0571  Bus Master IDE
-	0576  VT82C576 [Apollo Master]
+	0576  VT82C576 3V [Apollo Master]
 	0585  VT82C585VP [Apollo VP1/VPX]
 	0586  VT82C586/A/B PCI-to-ISA [Apollo VP]
 		1106 0000  MVP3 ISA Bridge
@@ -1973,12 +2027,12 @@
 		1106 0686  VT82C686/A PCI to ISA Bridge
 	0691  VT82C693A/694x [Apollo PRO133x]
 		1458 0691  VT82C691 Apollo Pro System Controller
-	0698  VT82C693A [Apollo Pro133 AGP]
 	0693  VT82C693 [Apollo Pro Plus]
+	0698  VT82C693A [Apollo Pro133 AGP]
 	0926  VT82C926 [Amazon]
 	1000  VT82C570MV
 	1106  VT82C570MV
-	1571  VT82C576 IDE [Apollo Master]
+	1571  VT82C416MV
 	1595  VT82C595/97 [Apollo VP2/97]
 	3038  UHCI USB
 		1234 0925  MVP3 USB Controller
@@ -2012,8 +2066,8 @@
 	8598  VT82C598/694x [Apollo MVP3/Pro133x AGP]
 	8601  VT8601 [Apollo ProMedia AGP]
 	8605  VT8605 [PM133 AGP]
-	B091  VT8633 [Apollo Pro266 AGP]
-	B099  VT8367 [KT266 AGP]
+	b091  VT8633 [Apollo Pro266 AGP]
+	b099  VT8367 [KT266 AGP]
 	8691  VT82C691 [Apollo Pro]
 1107  Stratus Computers
 	0576  VIA VT82C570MV [Apollo] (Wrong vendor ID!)
@@ -2073,7 +2127,7 @@
 1118  Berg Electronics
 1119  ICP Vortex Computersysteme GmbH
 	0000  GDT 6000/6020/6050
-	0001  GDT 6000b/6010
+	0001  GDT 6000B/6010
 	0002  GDT 6110/6510
 	0003  GDT 6120/6520
 	0004  GDT 6530
@@ -2081,9 +2135,9 @@
 	0006  GDT 6x17
 	0007  GDT 6x27
 	0008  GDT 6537
-	0009  GDT 5557
-	000a  GDT 6x15
-	000b  GDT 6x25
+	0009  GDT 6557
+	000a  GDT 6115/6515
+	000b  GDT 6125/6525
 	000c  GDT 6535
 	000d  GDT 6555
 	0100  GDT 6117RP/6517RP
@@ -2092,30 +2146,34 @@
 	0103  GDT 6557RP
 	0104  GDT 6111RP/6511RP
 	0105  GDT 6121RP/6521RP
-	0110  GDT 6117RP1/6517RP1
-	0111  GDT 6127RP1/6527RP1
-	0112  GDT 6537RP1
-	0113  GDT 6557RP1
-	0114  GDT 6111RP1/6511RP1
-	0115  GDT 6121RP1/6521RP1
-	0118  GDT 6x18RD
-	0119  GDT 6x28RD
-	011a  GDT 6x38RD
-	011b  GDT 6x58RD
-	0120  GDT 6117RP2/6517RP2
-	0121  GDT 6127RP2/6527RP2
-	0122  GDT 6537RP2
-	0123  GDT 6557RP2
-	0124  GDT 6111RP2/6511RP2
-	0125  GDT 6121RP2/6521RP2
-	0168  GDT 7x18RN
-	0169  GDT 7x28RN
-	016a  GDT 7x38RN
-	016b  GDT 7x58RN
-	0210  GDT 6x19RD
-	0211  GDT 6x29RD
-	0260  GDT 7x19RN
-	0261  GDT 7x29RN
+	0110  GDT 6117RD/6517RD
+	0111  GDT 6127RD/6527RD
+	0112  GDT 6537RD
+	0113  GDT 6557RD
+	0114  GDT 6111RD/6511RD
+	0115  GDT 6121RD/6521RD
+	0118  GDT 6118RD/6518RD/6618RD
+	0119  GDT 6128RD/6528RD/6628RD
+	011a  GDT 6538RD/6638RD
+	011b  GDT 6558RD/6658RD
+	0138  GDT 6118RS/6518RS/6618RS
+	0139  GDT 6128RS/6528RS/6628RS
+	013a  GDT 6538RS/6638RS
+	013b  GDT 6558RS/6658RS
+	0166  GDT 7113RN/7513RN/7613RN
+	0167  GDT 7123RN/7523RN/7623RN
+	0168  GDT 7118RN/7518RN/7518RN
+	0169  GDT 7128RN/7528RN/7628RN
+	016a  GDT 7538RN/7638RN
+	016b  GDT 7558RN/7658RN
+	016c  GDT 7533RN/7633RN
+	016d  GDT 7543RN/7643RN
+	016e  GDT 7553RN/7653RN
+	016f  GDT 7563RN/7663RN
+	0210  GDT 6519RD/6619RD
+	0211  GDT 6529RD/6629RD
+	0260  GDT 7519RN/7619RN
+	0261  GDT 7529RN/7629RN
 111a  Efficient Networks, Inc
 	0000  155P-MF1 (FPGA)
 	0002  155P-MF1 (ASIC)
@@ -2235,7 +2293,7 @@
 1145  Workbit Corporation
 1146  Force Computers
 1147  Interface Corp
-1148  SysKonnect GmbH
+1148  Syskonnect (Schneider & Koch)
 	4000  FDDI Adapter
 		0e11 b03b  Netelligent 100 FDDI DAS Fibre SC
 		0e11 b03c  Netelligent 100 FDDI SAS Fibre SC
@@ -2252,7 +2310,7 @@
 		1148 5841  FDDI SK-5841 (SK-NET FDDI-FP64)
 		1148 5843  FDDI SK-5843 (SK-NET FDDI-LP64)
 		1148 5844  FDDI SK-5844 (SK-NET FDDI-LP64 DAS)
-	4200  Token Ring adapter
+	4200  Token ring adaptor
 	4300  Gigabit Ethernet
 		1148 9821  SK-9821 (1000Base-T single link)
 		1148 9822  SK-9822 (1000Base-T dual link)
@@ -2429,6 +2487,7 @@
 118b  Hypertec Pty Limited
 118c  Corollary, Inc
 	0014  PCIB [C-bus II to PCI bus host bridge chip]
+	1117  Intel 8-way XEON Profusion Chipset [Cache Coherency Filter]
 118d  BitFlow Inc
 	0001  Raptor-PCI framegrabber
 	0012  Model 12 Road Runner Frame Grabber
@@ -2478,7 +2537,7 @@
 	1221  82C092G
 119c  Information Technology Inst.
 119d  Bug, Inc. Sapporo Japan
-119e  Fujitsu Microelectronics Europe GMBH
+119e  Fujitsu Microelectronics Ltd.
 	0001 FireStream 155
 	0003 FireStream 50
 119f  Bull HN Information Systems
@@ -2692,6 +2751,7 @@
 11f5  Computing Devices International
 11f6  Compex
 	0112  ENet100VG4
+	0113  FreedomLine 100
 	1401  ReadyLink 2000
 	2011  RL100-ATX 10/100
 	2201  ReadyLink 100TX (Winbond W89C840)
@@ -2803,7 +2863,8 @@
 		121a 0060  Voodoo3 3500 TV (NTSC)
 		121a 0061  Voodoo3 3500 TV (PAL)
 		121a 0062  Voodoo3 3500 TV (SECAM)
-	0009  Voodoo 4
+	0009  Voodoo 4 / Voodoo 5
+		121a 0009  Voodoo5 AGP 5500/6000
 121b  Advanced Telecommunications Modules
 121c  Nippon Texaco., Ltd
 121d  Lippert Automationstechnik GmbH
@@ -3029,13 +3090,13 @@
 		8086 5753  ES1371, ES1373 AudioPCI On Motherboard WS440BX
 	5000  ES1370 [AudioPCI]
 		4942 4c4c  Creative Sound Blaster AudioPCI128
-	5880  CT5880 [AudioPCI]
+	5880  5880 AudioPCI
 		1274 2000  Creative Sound Blaster AudioPCI128
 		1274 5880  Creative Sound Blaster AudioPCI128
-		1462 6880  CT5880 AudioPCI On Motherboard MS-6188 1.00
-		270f 2001  CT5880 AudioPCI On Motherboard 6CTR
-		270f 2200  CT5880 AudioPCI On Motherboard 6WTX
-		270f 7040  CT5880 AudioPCI On Motherboard 6ATA4
+		1462 6880  5880 AudioPCI On Motherboard MS-6188 1.00
+		270f 2001  5880 AudioPCI On Motherboard 6CTR
+		270f 2200  5880 AudioPCI On Motherboard 6WTX
+		270f 7040  5880 AudioPCI On Motherboard 6ATA4
 1275  Network Appliance Corporation
 1276  Switched Network Technologies, Inc.
 1277  Comstream
@@ -3146,8 +3207,9 @@
 12ac  Measurex Corporation
 12ad  Multidata GmbH
 12ae  Alteon Networks Inc.
-	0001  AceNIC Gigabit Ethernet
+	0001  AceNIC Gigabit Ethernet (Fibre)
 		1410 0104  Gigabit Ethernet-SX PCI Adapter (14100401)
+	0002  AceNIC Gigabit Ethernet (Copper)
 12af  TDK USA Corp
 12b0  Jorge Scientific Corp
 12b1  GammaLink
@@ -3368,7 +3430,8 @@
 1312  Acuity Imaging, Inc
 1313  Yaskawa Electric Co.
 1316  Teradyne Inc
-1317  Bridgecom, Inc
+1317  Linksys
+	0985  Network Everywhere Fast Ethernet 10/100 model NC100
 1318  Packet Engines Inc.
 	0911  PCI Ethernet Adapter
 1319  Fortemedia, Inc
@@ -3528,6 +3591,7 @@
 1384  Reality Simulation Systems Inc
 1385  Netgear
 	620a  GA620
+	f311  FA311
 1386  Video Domain Technologies
 1387  Systran Corp
 1388  Hitachi Information Technology Co Ltd
@@ -3920,7 +3984,31 @@
 14e2  INFOLIBRIA
 14e3  AMTELCO
 14e4  BROADCOM Corporation
-	1644  Tigon3
+	1644  NetXtreme BCM5700 Gigabit Ethernet
+		10b7 1000  3C996-T 1000BaseTX
+		10b7 1001  3C996B-T 1000BaseTX
+		10b7 1002  3C996C-T 1000BaseTX
+		10b7 1003  3C997-T 1000BaseTX
+		10b7 1004  3C996-SX 1000BaseSX
+		10b7 1005  3C997-SX 1000BaseSX
+		14e4 0002  NetXtreme 1000BaseSX
+		14e4 0003  NetXtreme 1000BaseSX
+		14e4 0004  NetXtreme 1000BaseTX
+		14e4 1644  NetXtreme BCM5700 1000BaseTX
+	1645  NetXtreme BCM5701 Gigabit Ethernet
+		0e11 007d  NC6770 1000BaseSX
+		0e11 007c  NC7770 1000BaseTX
+		0e11 0085  NC7780 1000BaseTX
+		10b7 1004  3C996-SX 1000BaseSX
+		10b7 1006  3C996B-T 1000BaseTX
+		10b7 1007  3C1000-T 1000BaseTX
+		10b7 1008  3C940-BR01 1000BaseTX
+		14e4 0001  NetXtreme BCM5701 1000BaseTX
+		14e4 0005  NetXtreme BCM5701 1000BaseTX
+		14e4 0006  NetXtreme BCM5701 1000BaseTX
+		14e4 0007  NetXtreme BCM5701 1000BaseSX
+		14e4 0008  NetXtreme BCM5701 1000BaseTX
+		14e4 8008  NetXtreme BCM5701 1000BaseTX
 14e5  Pixelfusion Ltd
 14e6  SHINING Technology Inc
 14e7  3CX
@@ -3955,6 +4043,8 @@
 		14f1 2015  SoftK56 Speakerphone Winmodem
 	2016  SoftK56 Speakerphone Winmodem
 		14f1 2016  SoftK56 Speakerphone Winmodem
+	2443  SoftK56 Speakerphone Winmodem
+		14f1 2443  SoftK56 Speakerphone Winmodem
 14f2  MOBILITY Electronics
 14f3  BROADLOGIC
 14f4  TOKYO Electronic Industry CO Ltd
@@ -3979,7 +4069,7 @@
 # 1507  HTEC Ltd
 # Commented out because there are no known HTEC chips and 1507 is already
 # used by mistake by Motorola (see vendor ID 1057)
-1507  Motorola ? / HTEC
+1507  Motorola ?? / HTEC
 	0001  MPC105 [Eagle]
 	0002  MPC106 [Grackle]
 	0003  MPC8240 [Kahlua]
@@ -4300,7 +4390,7 @@
 270b  Xantel Corporation
 270f  Chaintech Computer Co. Ltd
 2711  AVID Technology Inc.
-2a15  3D Vision(?)
+2a15  3D Vision(???)
 3000  Hansol Electronics Inc.
 3142  Post Impression Systems.
 3388  Hint Corp
@@ -4332,6 +4422,7 @@
 		3d3d 0125  Oxygen VX1
 		3d3d 0127  Permedia3 Create!
 	000a  GLINT R3
+		3d3d 0121  Oxygen VX1
 	0100  Permedia II 2D+3D
 	1004  Permedia
 	3d04  Permedia
@@ -4476,12 +4567,16 @@
 		5333 9125  86C394-397 Savage4 SGRAM 125
 		5333 9143  86C394-397 Savage4 SGRAM 143
 	8a23  Savage 4
+	8a25  ProSavage PM133
+	8a26  ProSavage KM133
 	8c00  ViRGE/M3
 	8c01  ViRGE/MX
 	8c02  ViRGE/MX+
 	8c03  ViRGE/MX+MV
-	8c10  86C270-294 Savage/MX-/IX
-	8c12  86C270-294 Savage/MX-/IX
+	8c10  86C270-294 Savage/MX-MV
+	8c11  82C270-294 Savage/MX
+	8c12  86C270-294 Savage/IX-MV
+	8c13  86C270-294 Savage/IX
 	9102  86C410 Savage 2000
 		1092 5932  Viper II Z200
 		1092 5934  Viper II Z200
@@ -4496,6 +4591,8 @@
 5455  Technische University Berlin
 	4458  S5933
 5519  Cnet Technologies, Inc.
+5544  Dunord Technologies
+	0001  I-30xx Scanner Interface
 5555  Genroco, Inc
 	0003  TURBOstor HFP-832 [HiPPI NIC]
 5700  Netpower
@@ -4523,22 +4620,37 @@
 	04a3  82434LX [Mercury/Neptune]
 	04d0  82437FX [Triton FX]
 	0960  80960RP [i960 RP Microprocessor/Bridge]
-	1000  82542 Gigabit Ethernet Adapter
+	0964  80960RP [i960 RP Microprocessor/Bridge]
+	1000  82542 Gigabit Ethernet Controller
 		0e11 b0df  NC1632 Gigabit Ethernet Adapter
 		0e11 b0e0  NC1633 Gigabit Ethernet Adapter
 		0e11 b123  NC1634 Gigabit Ethernet Adapter
 		1014 0119  Netfinity Gigabit Ethernet SX Adapter
-		8086 1000  EtherExpress PRO/1000 Gigabit Server Adapter
+	1001  82543GC Gigabit Ethernet Controller
+	1004  82543GC Gigabit Ethernet Controller
+	1008  82544EI Gigabit Ethernet Controller
+	100c  82544GC Gigabit Ethernet Controller
+	100d  82544GC Gigabit Ethernet Controller
 	1030  82559 InBusiness 10/100
+	1031  82801CAM (ICH3) Chipset Ethernet Controller
+	1032  82801CAM (ICH3) Chipset Ethernet Controller
+	1033  82801CAM (ICH3) Chipset Ethernet Controller
+	1034  82801CAM (ICH3) Chipset Ethernet Controller
+	1035  82801CAM (ICH3) Chipset Ethernet Controller
+	1036  82801CAM (ICH3) Chipset Ethernet Controller
+	1037  82801CAM (ICH3) Chipset Ethernet Controller
+	1038  82801CAM (ICH3) Chipset Ethernet Controller
+	1130  82815 815 Chipset Host Bridge and Memory Controller Hub
+	1132  82815 CGC [Chipset Graphics Controller] 
 	1161  82806AA PCI64 Hub Advanced Programmable Interrupt Controller
 	1209  82559ER
 	1221  82092AA_0
 	1222  82092AA_1
 	1223  SAA7116
 	1225  82452KX/GX [Orion]
-	1226  82596
-	1227  82865 [Ether Express Pro 100]
-	1228  82556 [Ether Express Pro 100 Smart]
+	1226  82596 PRO/10 PCI
+	1227  82865 EtherExpress PRO/100A
+	1228  82556 EtherExpress PRO/100 Smart
 	1229  82557 [Ethernet Pro 100]
 		0e11 b01e  NC3120
 		0e11 b01f  NC3122
@@ -4550,6 +4662,7 @@
 		0e11 b0dd  NC3131
 		0e11 b0de  NC3132
 		0e11 b0e1  NC3133
+		0e11 b144  NC3123 (82559)
 		1014 005c  82558B Ethernet Pro 10/100
 		1014 105c  Netfinity 10/100
 		1033 8000  PC-9821X-B06
@@ -4604,6 +4717,9 @@
 	1960  80960RP [i960RP Microprocessor]
 		101e 0438  MegaRaid 438
 		101e 0466  MegaRaid 466
+		101e 0467  MegaRaid 467
+		1028 0467  PowerEdge Expandable RAID Controller 2/DC
+		1028 1111  PowerEdge Expandable RAID Controller 2/SC
 		103c 10c6  MegaRaid 438
 		103c 10c7  MegaRaid T5
 		1111 1111  MegaRaid 466
@@ -4630,18 +4746,18 @@
 		11d4 0048  SoundMAX Integrated Digital Audio
 	2426  82801AB AC'97 Modem
 	2428  82801AB PCI Bridge
-	2440  82801BA ISA Bridge (ICH2)
-	2442  82801BA(M) USB (Hub A)
-	2443  82801BA(M) SMBus
-	2444  82801BA(M) USB (Hub B)
-	2445  82801BA(M) AC'97 Audio
-	2446  82801BA(M) AC'97 Modem
-	2448  82801BA PCI
-	2449  82801BA(M) Ethernet
-	244a  82801BAM IDE U100
-	244b  82801BA IDE U100
-	244c  82801BAM ISA Bridge (ICH2)
-	244e  82801BAM PCI
+	2440  82820 820 (Camino 2) Chipset ISA Bridge (ICH2)
+	2442  82820 820 (Camino 2) Chipset USB (Hub A)
+	2443  82820 820 (Camino 2) Chipset SMBus
+	2444  82820 820 (Camino 2) Chipset USB (Hub B)
+	2445  82820 820 (Camino 2) Chipset AC'97 Audio Controller
+	2446  82820 820 (Camino 2) Chipset AC'97 Modem Controller
+	2448  82820 820 (Camino 2) Chipset PCI (-M)
+	2449  82820 (ICH2) Chipset Ethernet Controller
+	244a  82820 820 (Camino 2) Chipset IDE U100 (-M)
+	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
 	2500  82820 820 (Camino) Chipset Host Bridge (MCH)
 		1043 801c  P3C-2000 system chipset
 	2501  82820 820 (Camino) Chipset Host Bridge (MCH)
@@ -4651,10 +4767,13 @@
 	2520  82805AA MTH Memory Translator Hub
 	2521  82804AA MRH-S Memory Repeater Hub for SDRAM
 	2530  82850 850 (Tehama) Chipset Host Bridge (MCH)
+	2531  82850 860 (Wombat) Chipset Host Bridge (MCH)
 	2532  82850 850 (Tehama) Chipset AGP Bridge
-	5200  EtherExpress PRO/100
-	5201  EtherExpress PRO/100
+	2533  82860 860 (Wombat) Chipset AGP Bridge
+	5200  EtherExpress PRO/100 Intelligent Server
+	5201  EtherExpress PRO/100 Intelligent Server
 		8086 0001  EtherExpress PRO/100 Server Ethernet Adapter
+	530d  80310 IOP [IO Processor]
 	7000  82371SB PIIX3 ISA [Natoma/Triton II]
 	7010  82371SB PIIX3 IDE [Natoma/Triton II]
 	7020  82371SB PIIX3 USB [Natoma/Triton II]
@@ -4717,7 +4836,7 @@
 9004  Adaptec
 # FIXME: [dj] In one document I have, lot of these AIC's are actually AHA's
 	1078  AIC-7810
-	1160  AIC-1160 [Family Fiber Channel Adapter]
+	1160  AIC-1160 [Family Fibre Channel Adapter]
 	2178  AIC-7821
 	3860  AHA-2930CU
 	3b78  AHA-4844W/4844UW
@@ -4834,6 +4953,7 @@
 	00c0  7899A
 	00c1  7899B
 	00c3  7899D
+	00c5  RAID subsystem HBA
 	00cf  7899P
 907f  Atronics
 	2015  IDE-2015PL
@@ -5017,7 +5137,7 @@
 		10  OHCI
 		80  Unspecified
 		Fe  USB Device
-	04  Fiber Channel
+	04  Fibre Channel
 	05  SMBus
 	06  InfiniBand
 C 0d  Wireless controller
diff -urN linux-2.4.11-pre2/drivers/scsi/st.c linux/drivers/scsi/st.c
--- linux-2.4.11-pre2/drivers/scsi/st.c	Mon Dec  3 23:15:30 2001
+++ linux/drivers/scsi/st.c	Mon Dec  3 23:15:40 2001
@@ -12,7 +12,7 @@
    Copyright 1992 - 2001 Kai Makisara
    email Kai.Makisara@metla.fi
 
-   Last modified: Sun Aug 12 12:34:28 2001 by makisara@kai.makisara.local
+   Last modified: Wed Oct  3 22:17:59 2001 by makisara@kai.makisara.local
    Some small formal changes - aeb, 950809
 
    Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
@@ -21,7 +21,7 @@
    error handling will be discarded.
  */
 
-static char *verstr = "20010812";
+static char *verstr = "20011003";
 
 #include <linux/module.h>
 
@@ -89,6 +89,8 @@
 MODULE_PARM(max_sg_segs, "i");
 MODULE_PARM_DESC(max_sg_segs, "Maximum number of scatter/gather segments to use (32)");
 
+EXPORT_NO_SYMBOLS;
+
 #ifndef MODULE
 static struct st_dev_parm {
 	char *name;
@@ -669,6 +671,7 @@
 
 	if (STp->device->host->hostt->module)
 		__MOD_INC_USE_COUNT(STp->device->host->hostt->module);
+	STp->device->access_count++;
 
 	if (!scsi_block_when_processing_errors(STp->device)) {
 		retval = (-ENXIO);
@@ -909,6 +912,7 @@
 		STp->buffer = NULL;
 	}
 	STp->in_use = 0;
+	STp->device->access_count--;
 	if (STp->device->host->hostt->module)
 	    __MOD_DEC_USE_COUNT(STp->device->host->hostt->module);
 	return retval;
@@ -1066,6 +1070,7 @@
 
 	STp->in_use = 0;
 	write_unlock_irqrestore(&st_dev_arr_lock, flags);
+	STp->device->access_count--;
 	if (STp->device->host->hostt->module)
 		__MOD_DEC_USE_COUNT(STp->device->host->hostt->module);
 
diff -urN linux-2.4.11-pre2/drivers/video/clgenfb.c linux/drivers/video/clgenfb.c
--- linux-2.4.11-pre2/drivers/video/clgenfb.c	Tue Jul 17 18:53:55 2001
+++ linux/drivers/video/clgenfb.c	Mon Dec  3 23:15:40 2001
@@ -31,7 +31,7 @@
  *
  */
 
-#define CLGEN_VERSION "1.9.8"
+#define CLGEN_VERSION "1.9.9"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -273,6 +273,7 @@
 	{ BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_5434_8 },
 	{ BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_5434_4 },
 	{ BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_5430 }, /* GD-5440 has identical id */
+	{ BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_7543 },
 	{ BT_GD5480, NULL, PCI_DEVICE_ID_CIRRUS_5480 }, /* MacPicasso probably */
 	{ BT_PICASSO4, NULL, PCI_DEVICE_ID_CIRRUS_5446 }, /* Picasso 4 is a GD5446 */
 	{ BT_LAGUNA, "CL Laguna", PCI_DEVICE_ID_CIRRUS_5462 },
diff -urN linux-2.4.11-pre2/drivers/video/controlfb.c linux/drivers/video/controlfb.c
--- linux-2.4.11-pre2/drivers/video/controlfb.c	Thu Sep 13 16:04:43 2001
+++ linux/drivers/video/controlfb.c	Mon Dec  3 23:15:40 2001
@@ -51,6 +51,7 @@
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/pgtable.h>
+#include <asm/btext.h>
 
 #include <video/fbcon.h>
 #include <video/fbcon-cfb8.h>
@@ -757,6 +758,12 @@
 		console_fb_info = &p->info;
 	}
 #endif /* CONFIG_FB_COMPAT_XPMAC */
+#ifdef CONFIG_BOOTX_TEXT
+	btext_update_display(p->frame_buffer_phys + CTRLFB_OFF,
+			     p->par.xres, p->par.yres,
+			     (cmode == CMODE_32? 32: cmode == CMODE_16? 16: 8),
+			     p->par.pitch);
+#endif /* CONFIG_BOOTX_TEXT */
 }
 
 
diff -urN linux-2.4.11-pre2/drivers/video/offb.c linux/drivers/video/offb.c
--- linux-2.4.11-pre2/drivers/video/offb.c	Fri Sep 14 14:04:07 2001
+++ linux/drivers/video/offb.c	Mon Dec  3 23:15:40 2001
@@ -32,7 +32,9 @@
 #endif
 #include <asm/io.h>
 #include <asm/prom.h>
+#ifdef CONFIG_BOOTX_TEXT
 #include <asm/bootx.h>
+#endif
 
 #include <video/fbcon.h>
 #include <video/fbcon-cfb8.h>
@@ -95,8 +97,9 @@
 			struct fb_info *info);
 static int offb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
 			struct fb_info *info);
-
+#ifdef CONFIG_BOOTX_TEXT
 extern boot_infos_t *boot_infos;
+#endif
 
 static void offb_init_nodriver(struct device_node *);
 static void offb_init_fb(const char *name, const char *full_name, int width,
@@ -253,6 +256,7 @@
 {
     struct device_node *dp;
     unsigned int dpy;
+#ifdef CONFIG_BOOTX_TEXT
     struct device_node *displays = find_type_devices("display");
     struct device_node *macos_display = NULL;
 
@@ -315,6 +319,7 @@
 		     boot_infos->dispDeviceDepth,
 		     boot_infos->dispDeviceRowBytes, addr, NULL);
     }
+#endif
 
     for (dpy = 0; dpy < prom_num_displays; dpy++) {
 	if ((dp = find_path_device(prom_display_paths[dpy])))
@@ -426,7 +431,8 @@
 		unsigned long regbase = dp->addrs[2].address;
 		info->cmap_adr = ioremap(regbase, 0x1FFF);
 		info->cmap_type = cmap_r128;
-	} else if (dp && !strncmp(name, "ATY,RageM3pA", 12)) {
+	} else if (dp && (!strncmp(name, "ATY,RageM3pA", 12)
+		|| !strncmp(name, "ATY,RageM3p12A", 14))) {
 		unsigned long regbase = dp->parent->addrs[2].address;
 		info->cmap_adr = ioremap(regbase, 0x1FFF);
 		info->cmap_type = cmap_M3A;
diff -urN linux-2.4.11-pre2/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- linux-2.4.11-pre2/fs/binfmt_elf.c	Mon Dec  3 23:15:30 2001
+++ linux/fs/binfmt_elf.c	Mon Dec  3 23:15:40 2001
@@ -76,6 +76,8 @@
 	NULL, THIS_MODULE, load_elf_binary, load_elf_library, elf_core_dump, ELF_EXEC_PAGESIZE
 };
 
+#define BAD_ADDR(x)	((unsigned long)(x) > TASK_SIZE)
+
 static void set_brk(unsigned long start, unsigned long end)
 {
 	start = ELF_PAGEALIGN(start);
@@ -298,6 +300,8 @@
 	    	elf_type |= MAP_FIXED;
 
 	    map_addr = elf_map(interpreter, load_addr + vaddr, eppnt, elf_prot, elf_type);
+	    if (BAD_ADDR(map_addr))
+	    	goto out_close;
 
 	    if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
 		load_addr = map_addr - ELF_PAGESTART(vaddr);
@@ -649,6 +653,8 @@
 		}
 
 		error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, elf_prot, elf_flags);
+		if (BAD_ADDR(error))
+			continue;
 
 		if (!load_addr_set) {
 			load_addr_set = 1;
@@ -697,7 +703,7 @@
 		fput(interpreter);
 		kfree(elf_interpreter);
 
-		if (elf_entry == ~0UL) {
+		if (BAD_ADDR(elf_entry)) {
 			printk(KERN_ERR "Unable to load interpreter\n");
 			kfree(elf_phdata);
 			send_sig(SIGSEGV, current, 0);
diff -urN linux-2.4.11-pre2/fs/block_dev.c linux/fs/block_dev.c
--- linux-2.4.11-pre2/fs/block_dev.c	Mon Dec  3 23:15:30 2001
+++ linux/fs/block_dev.c	Mon Dec  3 23:15:40 2001
@@ -549,36 +549,23 @@
 	return res;
 }
 
-int blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags, int kind)
+static int do_open(struct block_device *bdev, struct inode *inode, struct file *file)
 {
-	int ret = -ENODEV;
-	kdev_t rdev = to_kdev_t(bdev->bd_dev); /* this should become bdev */
-	down(&bdev->bd_sem);
+	int ret = -ENXIO;
+	kdev_t dev = to_kdev_t(bdev->bd_dev);
 
+	down(&bdev->bd_sem);
 	lock_kernel();
 	if (!bdev->bd_op)
-		bdev->bd_op = get_blkfops(MAJOR(rdev));
+		bdev->bd_op = get_blkfops(MAJOR(dev));
 	if (bdev->bd_op) {
-		/*
-		 * This crockload is due to bad choice of ->open() type.
-		 * It will go away.
-		 * For now, block device ->open() routine must _not_
-		 * examine anything in 'inode' argument except ->i_rdev.
-		 */
-		struct file fake_file = {};
-		struct dentry fake_dentry = {};
-		ret = -ENOMEM;
-		fake_file.f_mode = mode;
-		fake_file.f_flags = flags;
-		fake_file.f_dentry = &fake_dentry;
-		fake_dentry.d_inode = bdev->bd_inode;
 		ret = 0;
 		if (bdev->bd_op->open)
-			ret = bdev->bd_op->open(bdev->bd_inode, &fake_file);
+			ret = bdev->bd_op->open(inode, file);
 		if (!ret) {
 			bdev->bd_openers++;
-			bdev->bd_inode->i_size = blkdev_size(rdev);
-			bdev->bd_inode->i_blkbits = blksize_bits(block_size(rdev));
+			bdev->bd_inode->i_size = blkdev_size(dev);
+			bdev->bd_inode->i_blkbits = blksize_bits(block_size(dev));
 		} else if (!bdev->bd_openers)
 			bdev->bd_op = NULL;
 	}
@@ -589,9 +576,26 @@
 	return ret;
 }
 
+int blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags, int kind)
+{
+	/*
+	 * This crockload is due to bad choice of ->open() type.
+	 * It will go away.
+	 * For now, block device ->open() routine must _not_
+	 * examine anything in 'inode' argument except ->i_rdev.
+	 */
+	struct file fake_file = {};
+	struct dentry fake_dentry = {};
+	fake_file.f_mode = mode;
+	fake_file.f_flags = flags;
+	fake_file.f_dentry = &fake_dentry;
+	fake_dentry.d_inode = bdev->bd_inode;
+
+	return do_open(bdev, bdev->bd_inode, &fake_file);
+}
+
 int blkdev_open(struct inode * inode, struct file * filp)
 {
-	int ret;
 	struct block_device *bdev;
 
 	/*
@@ -604,29 +608,8 @@
 
 	bd_acquire(inode);
 	bdev = inode->i_bdev;
-	down(&bdev->bd_sem);
-
-	ret = -ENXIO;
-	lock_kernel();
-	if (!bdev->bd_op)
-		bdev->bd_op = get_blkfops(MAJOR(inode->i_rdev));
 
-	if (bdev->bd_op) {
-		ret = 0;
-		if (bdev->bd_op->open)
-			ret = bdev->bd_op->open(inode,filp);
-		if (!ret) {
-			bdev->bd_openers++;
-			bdev->bd_inode->i_size = blkdev_size(inode->i_rdev);
-		} else if (!bdev->bd_openers)
-			bdev->bd_op = NULL;
-	}	
-
-	unlock_kernel();
-	up(&bdev->bd_sem);
-	if (ret)
-		bdput(bdev);
-	return ret;
+	return do_open(bdev, inode, filp);
 }	
 
 int blkdev_put(struct block_device *bdev, int kind)
diff -urN linux-2.4.11-pre2/fs/lockd/svc.c linux/fs/lockd/svc.c
--- linux-2.4.11-pre2/fs/lockd/svc.c	Mon Dec  3 23:15:30 2001
+++ linux/fs/lockd/svc.c	Mon Dec  3 23:15:40 2001
@@ -15,6 +15,7 @@
 #define __KERNEL_SYSCALLS__
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/init.h>
 
 #include <linux/sched.h>
 #include <linux/errno.h>
@@ -55,6 +56,7 @@
  */
 unsigned long			nlm_grace_period;
 unsigned long			nlm_timeout = LOCKD_DFLT_TIMEO;
+unsigned long			nlm_udpport, nlm_tcpport;
 
 static unsigned long set_grace_period(void)
 {
@@ -241,9 +243,9 @@
 		goto out;
 	}
 
-	if ((error = svc_makesock(serv, IPPROTO_UDP, 0)) < 0 
+	if ((error = svc_makesock(serv, IPPROTO_UDP, nlm_udpport)) < 0 
 #ifdef CONFIG_NFSD_TCP
-	 || (error = svc_makesock(serv, IPPROTO_TCP, 0)) < 0
+	 || (error = svc_makesock(serv, IPPROTO_TCP, nlm_tcpport)) < 0
 #endif
 		) {
 		if (warned++ == 0) 
@@ -323,6 +325,8 @@
 MODULE_DESCRIPTION("NFS file locking service version " LOCKD_VERSION ".");
 MODULE_PARM(nlm_grace_period, "10-240l");
 MODULE_PARM(nlm_timeout, "3-20l");
+MODULE_PARM(nlm_udpport, "0-65535l");
+MODULE_PARM(nlm_tcpport, "0-65535l");
 
 int
 init_module(void)
@@ -340,6 +344,24 @@
 	/* FIXME: delete all NLM clients */
 	nlm_shutdown_hosts();
 }
+#else
+/* not a module, so process bootargs
+ * lockd.udpport and lockd.tcpport
+ */
+
+static int __init udpport_set(char *str)
+{
+	nlm_udpport = simple_strtoul(str, NULL, 0);
+	return 1;
+}
+static int __init tcpport_set(char *str)
+{
+	nlm_tcpport = simple_strtoul(str, NULL, 0);
+	return 1;
+}
+__setup("lockd.udpport=", udpport_set);
+__setup("lockd.tcpport=", tcpport_set);
+
 #endif
 
 /*
diff -urN linux-2.4.11-pre2/fs/nfsd/export.c linux/fs/nfsd/export.c
--- linux-2.4.11-pre2/fs/nfsd/export.c	Fri Sep  7 10:48:39 2001
+++ linux/fs/nfsd/export.c	Mon Dec  3 23:15:40 2001
@@ -550,15 +550,15 @@
 	{ NFSEXP_INSECURE_PORT, {"insecure", ""}},
 	{ NFSEXP_ROOTSQUASH, {"root_squash", "no_root_squash"}},
 	{ NFSEXP_ALLSQUASH, {"all_squash", ""}},
-	{ NFSEXP_ASYNC, {"async", ""}},
-	{ NFSEXP_GATHERED_WRITES, {"wdelay", ""}},
+	{ NFSEXP_ASYNC, {"async", "sync"}},
+	{ NFSEXP_GATHERED_WRITES, {"wdelay", "no_wdelay"}},
 	{ NFSEXP_UIDMAP, {"uidmap", ""}},
 	{ NFSEXP_KERBEROS, { "kerberos", ""}},
 	{ NFSEXP_SUNSECURE, { "sunsecure", ""}},
 	{ NFSEXP_CROSSMNT, {"nohide", ""}},
 	{ NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}},
 	{ NFSEXP_NOAUTHNLM, {"insecure_locks", ""}},
-#ifdef NSMFS
+#ifdef MSNFS
 	{ NFSEXP_MSNFS, {"msnfs", ""}},
 #endif
 	{ 0, {"", ""}}
diff -urN linux-2.4.11-pre2/fs/nfsd/nfs3xdr.c linux/fs/nfsd/nfs3xdr.c
--- linux-2.4.11-pre2/fs/nfsd/nfs3xdr.c	Thu Sep 20 21:02:01 2001
+++ linux/fs/nfsd/nfs3xdr.c	Mon Dec  3 23:15:40 2001
@@ -99,7 +99,7 @@
 	char		*name;
 	int		i;
 
-	if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS3_MAXPATHLEN)) != NULL) {
+	if ((p = xdr_decode_string(p, namp, lenp, NFS3_MAXPATHLEN)) != NULL) {
 		for (i = 0, name = *namp; i < *lenp; i++, name++) {
 			if (*name == '\0')
 				return NULL;
diff -urN linux-2.4.11-pre2/fs/nfsd/nfsfh.c linux/fs/nfsd/nfsfh.c
--- linux-2.4.11-pre2/fs/nfsd/nfsfh.c	Thu Sep 20 21:02:01 2001
+++ linux/fs/nfsd/nfsfh.c	Mon Dec  3 23:15:40 2001
@@ -731,8 +731,10 @@
 {
 	struct super_block *sb = dentry->d_inode->i_sb;
 	
-	if (dentry == exp->ex_dentry)
+	if (dentry == exp->ex_dentry) {
+		*maxsize = 0;
 		return 0;
+	}
 
 	if (sb->s_op->dentry_to_fh) {
 		int need_parent = !S_ISDIR(dentry->d_inode->i_mode) &&
diff -urN linux-2.4.11-pre2/fs/nfsd/nfsxdr.c linux/fs/nfsd/nfsxdr.c
--- linux-2.4.11-pre2/fs/nfsd/nfsxdr.c	Mon Aug 13 12:23:49 2001
+++ linux/fs/nfsd/nfsxdr.c	Mon Dec  3 23:15:40 2001
@@ -65,7 +65,7 @@
 	char		*name;
 	int		i;
 
-	if ((p = xdr_decode_string(p, namp, lenp, NFS_MAXNAMLEN)) != NULL) {
+	if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS_MAXNAMLEN)) != NULL) {
 		for (i = 0, name = *namp; i < *lenp; i++, name++) {
 			if (*name == '\0' || *name == '/')
 				return NULL;
diff -urN linux-2.4.11-pre2/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- linux-2.4.11-pre2/fs/nfsd/vfs.c	Thu Sep 20 21:02:01 2001
+++ linux/fs/nfsd/vfs.c	Mon Dec  3 23:15:40 2001
@@ -227,7 +227,7 @@
 #define	MAX_TOUCH_TIME_ERROR (30*60)
 	if (err
 	    && (iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET
-	    && iap->ia_mtime == iap->ia_ctime
+	    && iap->ia_mtime == iap->ia_atime
 	    ) {
 	    /* looks good.  now just make sure time is in the right ballpark.
 	     * solaris, at least, doesn't seem to care what the time request is
diff -urN linux-2.4.11-pre2/fs/partitions/acorn.c linux/fs/partitions/acorn.c
--- linux-2.4.11-pre2/fs/partitions/acorn.c	Mon Sep 18 15:15:26 2000
+++ linux/fs/partitions/acorn.c	Mon Dec  3 23:15:40 2001
@@ -22,15 +22,16 @@
 #include "acorn.h"
 
 static void
-adfspart_setgeometry(kdev_t dev, unsigned int secspertrack, unsigned int heads,
-		     unsigned long totalblocks)
+adfspart_setgeometry(kdev_t dev, unsigned int secspertrack, unsigned int heads)
 {
+#ifdef CONFIG_BLK_DEV_MFM
 	extern void xd_set_geometry(kdev_t dev, unsigned char, unsigned char,
 				    unsigned long, unsigned int);
 
-#ifdef CONFIG_BLK_DEV_MFM
-	if (MAJOR(dev) == MFM_ACORN_MAJOR)
+	if (MAJOR(dev) == MFM_ACORN_MAJOR) {
+		unsigned long totalblocks = hd->part[MINOR(dev)].nr_sects;
 		xd_set_geometry(dev, secspertrack, heads, totalblocks, 1);
+	}
 #endif
 }
 
@@ -60,32 +61,26 @@
 
 #ifdef CONFIG_ACORN_PARTITION_RISCIX
 static int
-riscix_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sect,
-		 int minor, unsigned long nr_sects)
+riscix_partition(struct gendisk *hd, struct block_device *bdev,
+		unsigned long first_sect, int minor, unsigned long nr_sects)
 {
-	struct buffer_head *bh;
+	Sector sect;
 	struct riscix_record *rr;
-	unsigned int riscix_minor;
 	
-	if(get_ptable_blocksize(dev)!=1024)
-		return 0;
+	rr = (struct riscix_record *)read_dev_sector(bdev, first_sect, &sect);
+	if (!rr)
+		return -1;
 
 	printk(" [RISCiX]");
 
-	add_gd_partition(hd, riscix_minor = minor++, first_sect, nr_sects);
-	hd->sizes[riscix_minor] = hd->part[riscix_minor].nr_sects >>
-					(BLOCK_SIZE_BITS - 9);
-	dev = MKDEV(hd->major, riscix_minor);
-
-	if (!(bh = bread(dev, 0, 1024)))
-		return -1;
 
-	rr = (struct riscix_record *)bh->b_data;
 	if (rr->magic == RISCIX_MAGIC) {
+		unsigned long size = nr_sects > 2 ? 2 : nr_sects;
 		int part;
 
 		printk(" <");
 
+		add_gd_partition(hd, minor++, first_sect, size);
 		for (part = 0; part < 8; part++) {
 			if (rr->part[part].one &&
 			    memcmp(rr->part[part].name, "All\0", 4)) {
@@ -97,38 +92,32 @@
 		}
 
 		printk(" >\n");
-
-		if (hd->part[riscix_minor].nr_sects > 2)
-			hd->part[riscix_minor].nr_sects = 2;
+	} else {
+		add_gd_partition(hd, minor++, first_sect, nr_sects);
 	}
 
-	brelse(bh);
+	put_dev_sector(sect);
 	return minor;
 }
 #endif
 
 static int
-linux_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sect,
-		int minor, unsigned long nr_sects)
+linux_partition(struct gendisk *hd, struct block_device *bdev,
+		unsigned long first_sect, int minor, unsigned long nr_sects)
 {
-	struct buffer_head *bh;
+	Sector sect;
 	struct linux_part *linuxp;
-	unsigned int linux_minor, mask = (1 << hd->minor_shift) - 1;
+	unsigned int mask = (1 << hd->minor_shift) - 1;
+	unsigned long size = nr_sects > 2 ? 2 : nr_sects;
 
-	if(get_ptable_blocksize(dev)!=1024)
-		return 0;
-		
 	printk(" [Linux]");
 
-	add_gd_partition(hd, linux_minor = minor++, first_sect, nr_sects);
-	hd->sizes[linux_minor] = hd->part[linux_minor].nr_sects >>
-					(BLOCK_SIZE_BITS - 9);
-	dev = MKDEV(hd->major, linux_minor);
+	add_gd_partition(hd, minor++, first_sect, size);
 
-	if (!(bh = bread(dev, 0, 1024)))
+	linuxp = (struct linux_part *)read_dev_sector(bdev, first_sect, &sect);
+	if (!linuxp)
 		return -1;
 
-	linuxp = (struct linux_part *)bh->b_data;
 	printk(" <");
 	while (linuxp->magic == cpu_to_le32(LINUX_NATIVE_MAGIC) ||
 	       linuxp->magic == cpu_to_le32(LINUX_SWAP_MAGIC)) {
@@ -140,29 +129,22 @@
 		linuxp ++;
 	}
 	printk(" >");
-	/*
-	 * Prevent someone doing a mkswap or mkfs on this partition
-	 */
-	if(hd->part[linux_minor].nr_sects > 2)
-		hd->part[linux_minor].nr_sects = 2;
 
-	brelse(bh);
+	put_dev_sector(sect);
 	return minor;
 }
 
 #ifdef CONFIG_ACORN_PARTITION_CUMANA
 static int
-adfspart_check_CUMANA(struct gendisk *hd, kdev_t dev,
+adfspart_check_CUMANA(struct gendisk *hd, struct block_device *bdev,
 		      unsigned long first_sector, int minor)
 {
 	unsigned int start_blk = 0, mask = (1 << hd->minor_shift) - 1;
-	struct buffer_head *bh = NULL;
+	Sector sect;
+	unsigned char *data;
 	char *name = "CUMANA/ADFS";
 	int first = 1;
 
-	if(get_ptable_blocksize(dev)!=1024)
-		return 0;
-
 	/*
 	 * Try Cumana style partitions - sector 3 contains ADFS boot block
 	 * with pointer to next 'drive'.
@@ -183,16 +165,17 @@
 		if (!(minor & mask))
 			break;
 
-		if (!(bh = bread(dev, start_blk + 3, 1024)))
+		data = read_dev_sector(bdev, start_blk * 2 + 6, &sect);
+		if (!data)
 			return -1;
 
-		dr = adfs_partition(hd, name, bh->b_data,
-				    first_sector, minor++);
+		dr = adfs_partition(hd, name, data, first_sector, minor++);
 		if (!dr)
 			break;
+
 		name = NULL;
 
-		nr_sects = (bh->b_data[0x1fd] + (bh->b_data[0x1fe] << 8)) *
+		nr_sects = (data[0x1fd] + (data[0x1fe] << 8)) *
 			   (dr->heads + (dr->lowsector & 0x40 ? 1 : 0)) *
 			   dr->secspertrack;
 
@@ -204,30 +187,28 @@
 		start_blk += nr_sects >> (BLOCK_SIZE_BITS - 9);
 		nr_sects = 0; /* hmm - should be partition size */
 
-		switch (bh->b_data[0x1fc] & 15) {
+		switch (data[0x1fc] & 15) {
 		case 0: /* No partition / ADFS? */
 			break;
 
 #ifdef CONFIG_ACORN_PARTITION_RISCIX
 		case PARTITION_RISCIX_SCSI:
 			/* RISCiX - we don't know how to find the next one. */
-			minor = riscix_partition(hd, dev, first_sector,
+			minor = riscix_partition(hd, bdev, first_sector,
 						 minor, nr_sects);
 			break;
 #endif
 
 		case PARTITION_LINUX:
-			minor = linux_partition(hd, dev, first_sector,
+			minor = linux_partition(hd, bdev, first_sector,
 						minor, nr_sects);
 			break;
 		}
-		brelse(bh);
-		bh = NULL;
+		put_dev_sector(sect);
 		if (minor == -1)
 			return minor;
 	} while (1);
-	if (bh)
-		bforget(bh);
+	put_dev_sector(sect);
 	return first ? 0 : 1;
 }
 #endif
@@ -248,73 +229,73 @@
  *	    hda2 = non-ADFS partition.
  */
 static int
-adfspart_check_ADFS(struct gendisk *hd, kdev_t dev,
+adfspart_check_ADFS(struct gendisk *hd, struct block_device *bdev,
 		   unsigned long first_sector, int minor)
 {
 	unsigned long start_sect, nr_sects, sectscyl, heads;
-	struct buffer_head *bh;
+	Sector sect;
+	unsigned char *data;
 	struct adfs_discrecord *dr;
+	unsigned char id;
 
-	if(get_ptable_blocksize(dev)!=1024)
-		return 0;
-
-	if (!(bh = bread(dev, 3, 1024)))
+	data = read_dev_sector(bdev, 6, &sect);
+	if (!data)
 		return -1;
 
-	dr = adfs_partition(hd, "ADFS", bh->b_data, first_sector, minor++);
+	dr = adfs_partition(hd, "ADFS", data, first_sector, minor++);
 	if (!dr) {
-		bforget(bh);
+		put_dev_sector(sect);
     		return 0;
 	}
 
 	heads = dr->heads + ((dr->lowsector >> 6) & 1);
-	adfspart_setgeometry(dev, dr->secspertrack, heads,
-			     hd->part[MINOR(dev)].nr_sects);
 	sectscyl = dr->secspertrack * heads;
+	start_sect = ((data[0x1fe] << 8) + data[0x1fd]) * sectscyl;
+	id = data[0x1fc] & 15;
+	put_dev_sector(sect);
+
+	adfspart_setgeometry(to_kdev_t(bdev->bd_dev), dr->secspertrack, heads);
+	invalidate_bdev(bdev, 1);
+	truncate_inode_pages(bdev->bd_inode->i_mapping, 0);
 
 	/*
 	 * Work out start of non-adfs partition.
 	 */
-	start_sect = ((bh->b_data[0x1fe] << 8) + bh->b_data[0x1fd]) * sectscyl;
-	nr_sects = hd->part[MINOR(dev)].nr_sects - start_sect;
+	nr_sects = hd->part[MINOR(to_kdev_t(bdev->bd_dev))].nr_sects - start_sect;
 
 	if (start_sect) {
 		first_sector += start_sect;
 
-		switch (bh->b_data[0x1fc] & 15) {
+		switch (id) {
 #ifdef CONFIG_ACORN_PARTITION_RISCIX
 		case PARTITION_RISCIX_SCSI:
 		case PARTITION_RISCIX_MFM:
-			minor = riscix_partition(hd, dev, first_sector,
+			minor = riscix_partition(hd, bdev, first_sector,
 						 minor, nr_sects);
 			break;
 #endif
 
 		case PARTITION_LINUX:
-			minor = linux_partition(hd, dev, first_sector,
+			minor = linux_partition(hd, bdev, first_sector,
 						minor, nr_sects);
 			break;
 		}
 	}
-	brelse(bh);
 	return 1;
 }
 #endif
 
 #ifdef CONFIG_ACORN_PARTITION_ICS
-static int adfspart_check_ICSLinux(kdev_t dev, unsigned long block)
+static int adfspart_check_ICSLinux(struct block_device *bdev, unsigned long block)
 {
-	struct buffer_head *bh;
-	unsigned int offset = block & 1 ? 512 : 0;
+	Sector sect;
+	unsigned char *data = read_dev_sector(bdev, block, &sect);
 	int result = 0;
 
-	bh = bread(dev, block >> 1, 1024);
-
-	if (bh != NULL) {
-		if (memcmp(bh->b_data + offset, "LinuxPart", 9) == 0)
+	if (data) {
+		if (memcmp(data, "LinuxPart", 9) == 0)
 			result = 1;
-
-		brelse(bh);
+		put_dev_sector(sect);
 	}
 
 	return result;
@@ -333,38 +314,37 @@
  *		..etc..
  */
 static int
-adfspart_check_ICS(struct gendisk *hd, kdev_t dev,
+adfspart_check_ICS(struct gendisk *hd, struct block_device *bdev,
 		   unsigned long first_sector, int minor)
 {
-	struct buffer_head *bh;
+	Sector sect;
+	unsigned char *data;
 	unsigned long sum;
 	unsigned int i, mask = (1 << hd->minor_shift) - 1;
 	struct ics_part *p;
 
-	if(get_ptable_blocksize(dev)!=1024)
-		return 0;
-		
 	/*
 	 * Try ICS style partitions - sector 0 contains partition info.
 	 */
-	if (!(bh = bread(dev, 0, 1024)))
+	data = read_dev_sector(bdev, 0, &sect);
+	if (!data)
 	    	return -1;
 
 	/*
 	 * check for a valid checksum
 	 */
 	for (i = 0, sum = 0x50617274; i < 508; i++)
-		sum += bh->b_data[i];
+		sum += data[i];
 
-	sum -= le32_to_cpu(*(__u32 *)(&bh->b_data[508]));
+	sum -= le32_to_cpu(*(__u32 *)(&data[508]));
 	if (sum) {
-	    	bforget(bh);
+	    	put_dev_sector(sect);
 		return 0; /* not ICS partition table */
 	}
 
 	printk(" [ICS]");
 
-	for (p = (struct ics_part *)bh->b_data; p->size; p++) {
+	for (p = (struct ics_part *)data; p->size; p++) {
 		unsigned long start;
 		long size;
 
@@ -381,7 +361,7 @@
 			 * We use the first sector to identify what type
 			 * this partition is...
 			 */
-			if (size > 1 && adfspart_check_ICSLinux(dev, start)) {
+			if (size > 1 && adfspart_check_ICSLinux(bdev, start)) {
 				start += 1;
 				size -= 1;
 			}
@@ -393,12 +373,11 @@
 		}
 	}
 
-	brelse(bh);
+	put_dev_sector(sect);
 	return 1;
 }
 #endif
 
-#ifdef CONFIG_ACORN_PARTITION_POWERTEC
 /*
  * Purpose: allocate ICS partitions.
  * Params : hd		- pointer to gendisk structure to store partition info.
@@ -411,29 +390,32 @@
  *	    hda2 = ADFS partition 1 on first drive.
  *		..etc..
  */
+#ifdef CONFIG_ACORN_PARTITION_POWERTEC
 static int
-adfspart_check_POWERTEC(struct gendisk *hd, kdev_t dev,
+adfspart_check_POWERTEC(struct gendisk *hd, struct block_device *bdev,
 			unsigned long first_sector, int minor)
 {
-	struct buffer_head *bh;
+	Sector sect;
+	unsigned char *data;
 	struct ptec_partition *p;
 	unsigned char checksum;
 	int i;
 
-	if (!(bh = bread(dev, 0, 1024)))
+	data = read_dev_sector(bdev, 0, &sect);
+	if (!data)
 		return -1;
 
 	for (checksum = 0x2a, i = 0; i < 511; i++)
-		checksum += bh->b_data[i];
+		checksum += data[i];
 
-	if (checksum != bh->b_data[511]) {
-		bforget(bh);
+	if (checksum != data[511]) {
+		put_dev_sector(sect);
 		return 0;
 	}
 
 	printk(" [POWERTEC]");
 
-	for (i = 0, p = (struct ptec_partition *)bh->b_data; i < 12; i++, p++) {
+	for (i = 0, p = (struct ptec_partition *)data; i < 12; i++, p++) {
 		unsigned long start;
 		unsigned long size;
 
@@ -446,24 +428,24 @@
 		minor++;
 	}
 
-	brelse(bh);
+	put_dev_sector(sect);
 	return 1;
 }
 #endif
 
-static int (*partfn[])(struct gendisk *, kdev_t, unsigned long, int) = {
+static int (*partfn[])(struct gendisk *, struct block_device *, unsigned long, int) = {
 #ifdef CONFIG_ACORN_PARTITION_ICS
 	adfspart_check_ICS,
 #endif
+#ifdef CONFIG_ACORN_PARTITION_POWERTEC
+	adfspart_check_POWERTEC,
+#endif
 #ifdef CONFIG_ACORN_PARTITION_CUMANA
 	adfspart_check_CUMANA,
 #endif
 #ifdef CONFIG_ACORN_PARTITION_ADFS
 	adfspart_check_ADFS,
 #endif
-#ifdef CONFIG_ACORN_PARTITION_POWERTEC
-	adfspart_check_POWERTEC,
-#endif
 	NULL
 };
 /*
@@ -478,17 +460,18 @@
  *
  * Returns: -1 on error, 0 if not ADFS format, 1 if ok.
  */
-int acorn_partition(struct gendisk *hd, kdev_t dev,
+int acorn_partition(struct gendisk *hd, struct block_device *bdev,
 		    unsigned long first_sect, int first_minor)
 {
-	int r = 0, i;
-
-	for (i = 0; partfn[i] && r == 0; i++)
-		r = partfn[i](hd, dev, first_sect, first_minor);
+	int i;
 
-	if (r < 0 && warn_no_part)
-		printk(" unable to read boot sectors / partition sectors\n");
-	if (r > 0)
-		printk("\n");
-	return r;
+	for (i = 0; partfn[i]; i++) {
+		int r = partfn[i](hd, bdev, first_sect, first_minor);
+		if (r) {
+			if (r > 0)
+				printk("\n");
+			return r;
+		}
+	}
+	return 0;
 }
diff -urN linux-2.4.11-pre2/fs/partitions/acorn.h linux/fs/partitions/acorn.h
--- linux-2.4.11-pre2/fs/partitions/acorn.h	Sun Sep 23 10:32:56 2001
+++ linux/fs/partitions/acorn.h	Mon Dec  3 23:15:40 2001
@@ -50,6 +50,6 @@
 };
 	
 
-int acorn_partition(struct gendisk *hd, kdev_t dev,
+int acorn_partition(struct gendisk *hd, struct block_device *bdev,
 		   unsigned long first_sect, int first_minor);
 
diff -urN linux-2.4.11-pre2/fs/partitions/amiga.c linux/fs/partitions/amiga.c
--- linux-2.4.11-pre2/fs/partitions/amiga.c	Wed Feb 16 15:42:06 2000
+++ linux/fs/partitions/amiga.c	Mon Dec  3 23:15:40 2001
@@ -31,90 +31,82 @@
 }
 
 int
-amiga_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, int first_part_minor)
+amiga_partition(struct gendisk *hd, struct block_device *bdev,
+		unsigned long first_sector, int first_part_minor)
 {
-	struct buffer_head	*bh;
-	struct RigidDiskBlock	*rdb;
-	struct PartitionBlock	*pb;
-	int			 start_sect;
-	int			 nr_sects;
-	int			 blk;
-	int			 part, res;
-	int			 old_blocksize;
-	int			 blocksize;
-
-	old_blocksize = get_ptable_blocksize(dev);
-	blocksize = get_hardsect_size(dev);
-
-	if (blocksize < 512)
-		blocksize = 512;
-
-	set_blocksize(dev,blocksize);
-	res = 0;
-
-	for (blk = 0; blk < RDB_ALLOCATION_LIMIT; blk++) {
-		if(!(bh = bread(dev,blk,blocksize))) {
-			if (warn_no_part) printk("Dev %s: unable to read RDB block %d\n",
-			       kdevname(dev),blk);
+	Sector sect;
+	unsigned char *data;
+	struct RigidDiskBlock *rdb;
+	struct PartitionBlock *pb;
+	int start_sect, nr_sects, blk, part, res = 0;
+	kdev_t dev = to_kdev_t(bdev->bd_dev);
+
+	for (blk = 0; ; blk++, put_dev_sector(sect)) {
+		if (blk == RDB_ALLOCATION_LIMIT)
+			goto rdb_done;
+		data = read_dev_sector(bdev, blk, &sect);
+		if (!data) {
+			if (warn_no_part)
+				printk("Dev %s: unable to read RDB block %d\n",
+				       bdevname(dev), blk);
 			goto rdb_done;
 		}
-		if (*(u32 *)bh->b_data == cpu_to_be32(IDNAME_RIGIDDISK)) {
-			rdb = (struct RigidDiskBlock *)bh->b_data;
-			if (checksum_block((u32 *)bh->b_data,be32_to_cpu(rdb->rdb_SummedLongs) & 0x7F)) {
-				/* Try again with 0xdc..0xdf zeroed, Windows might have
-				 * trashed it.
-				 */
-				*(u32 *)(&bh->b_data[0xdc]) = 0;
-				if (checksum_block((u32 *)bh->b_data,
-						be32_to_cpu(rdb->rdb_SummedLongs) & 0x7F)) {
-					brelse(bh);
-					printk("Dev %s: RDB in block %d has bad checksum\n",
-					       kdevname(dev),blk);
-					continue;
-				}
-				printk("Warning: Trashed word at 0xd0 in block %d "
-					"ignored in checksum calculation\n",blk);
-			}
-			printk(" RDSK");
-			blk = be32_to_cpu(rdb->rdb_PartitionList);
-			brelse(bh);
-			for (part = 1; blk > 0 && part <= 16; part++) {
-				if (!(bh = bread(dev,blk,blocksize))) {
-					if (warn_no_part) printk("Dev %s: unable to read partition block %d\n",
-						       kdevname(dev),blk);
-					goto rdb_done;
-				}
-				pb  = (struct PartitionBlock *)bh->b_data;
-				blk = be32_to_cpu(pb->pb_Next);
-				if (pb->pb_ID == cpu_to_be32(IDNAME_PARTITION) && checksum_block(
-				    (u32 *)pb,be32_to_cpu(pb->pb_SummedLongs) & 0x7F) == 0 ) {
-
-					/* Tell Kernel about it */
-
-					if (!(nr_sects = (be32_to_cpu(pb->pb_Environment[10]) + 1 -
-							  be32_to_cpu(pb->pb_Environment[9])) *
-							 be32_to_cpu(pb->pb_Environment[3]) *
-							 be32_to_cpu(pb->pb_Environment[5]))) {
-						brelse(bh);
-						continue;
- 					}
-					start_sect = be32_to_cpu(pb->pb_Environment[9]) *
-						     be32_to_cpu(pb->pb_Environment[3]) *
-						     be32_to_cpu(pb->pb_Environment[5]);
-					add_gd_partition(hd,first_part_minor,start_sect,nr_sects);
-					first_part_minor++;
-					res = 1;
-				}
-				brelse(bh);
-			}
-			printk("\n");
+		if (*(u32 *)data != cpu_to_be32(IDNAME_RIGIDDISK))
+			continue;
+
+		rdb = (struct RigidDiskBlock *)data;
+		if (checksum_block((u32 *)data, be32_to_cpu(rdb->rdb_SummedLongs) & 0x7F) == 0)
 			break;
+		/* Try again with 0xdc..0xdf zeroed, Windows might have
+		 * trashed it.
+		 */
+		*(u32 *)(data+0xdc) = 0;
+		if (checksum_block((u32 *)data,
+				be32_to_cpu(rdb->rdb_SummedLongs) & 0x7F)==0) {
+			printk("Warning: Trashed word at 0xd0 in block %d "
+				"ignored in checksum calculation\n",blk);
+			break;
+		}
+
+		printk("Dev %s: RDB in block %d has bad checksum\n",
+			       bdevname(dev),blk);
+	}
+
+	printk(" RDSK");
+	blk = be32_to_cpu(rdb->rdb_PartitionList);
+	put_dev_sector(sect);
+	for (part = 1; blk>0 && part<=16; part++, put_dev_sector(sect)) {
+		data = read_dev_sector(bdev, blk, &sect);
+		if (!data) {
+			if (warn_no_part)
+				printk("Dev %s: unable to read partition block %d\n",
+				       bdevname(dev),blk);
+			goto rdb_done;
 		}
-		else
-			brelse(bh);
+		pb  = (struct PartitionBlock *)data;
+		blk = be32_to_cpu(pb->pb_Next);
+		if (pb->pb_ID != cpu_to_be32(IDNAME_PARTITION))
+			continue;
+		if (checksum_block((u32 *)pb, be32_to_cpu(pb->pb_SummedLongs) & 0x7F) != 0 )
+			continue;
+
+		/* Tell Kernel about it */
+
+		nr_sects = (be32_to_cpu(pb->pb_Environment[10]) + 1 -
+			    be32_to_cpu(pb->pb_Environment[9])) *
+			   be32_to_cpu(pb->pb_Environment[3]) *
+			   be32_to_cpu(pb->pb_Environment[5]);
+		if (!nr_sects)
+			continue;
+		start_sect = be32_to_cpu(pb->pb_Environment[9]) *
+			     be32_to_cpu(pb->pb_Environment[3]) *
+			     be32_to_cpu(pb->pb_Environment[5]);
+		add_gd_partition(hd,first_part_minor,start_sect,nr_sects);
+		first_part_minor++;
+		res = 1;
 	}
+	printk("\n");
 
 rdb_done:
-	set_blocksize(dev,old_blocksize);
 	return res;
 }
diff -urN linux-2.4.11-pre2/fs/partitions/amiga.h linux/fs/partitions/amiga.h
--- linux-2.4.11-pre2/fs/partitions/amiga.h	Thu Aug 12 12:26:06 1999
+++ linux/fs/partitions/amiga.h	Mon Dec  3 23:15:40 2001
@@ -3,6 +3,6 @@
  */
 
 int
-amiga_partition(struct gendisk *hd, kdev_t dev,
+amiga_partition(struct gendisk *hd, struct block_device *bdev,
 		unsigned long first_sector, int first_part_minor);
 
diff -urN linux-2.4.11-pre2/fs/partitions/atari.c linux/fs/partitions/atari.c
--- linux-2.4.11-pre2/fs/partitions/atari.c	Thu Oct 12 14:19:32 2000
+++ linux/fs/partitions/atari.c	Mon Dec  3 23:15:40 2001
@@ -33,146 +33,130 @@
      be32_to_cpu((pi)->st) <= (hdsiz) &&				     \
      be32_to_cpu((pi)->st) + be32_to_cpu((pi)->siz) <= (hdsiz))
 
-int atari_partition (struct gendisk *hd, kdev_t dev,
+static inline int OK_id(char *s)
+{
+	return  memcmp (s, "GEM", 3) == 0 || memcmp (s, "BGM", 3) == 0 ||
+		memcmp (s, "LNX", 3) == 0 || memcmp (s, "SWP", 3) == 0 ||
+		memcmp (s, "RAW", 3) == 0 ;
+}
+
+int atari_partition (struct gendisk *hd, struct block_device *bdev,
 		     unsigned long first_sector, int minor)
 {
-  int m_lim = minor + hd->max_p;
-  struct buffer_head *bh;
-  struct rootsector *rs;
-  struct partition_info *pi;
-  u32 extensect;
-  u32 hd_size;
+	int m_lim = minor + hd->max_p;
+	Sector sect;
+	struct rootsector *rs;
+	struct partition_info *pi;
+	u32 extensect;
+	u32 hd_size;
 #ifdef ICD_PARTS
-  int part_fmt = 0; /* 0:unknown, 1:AHDI, 2:ICD/Supra */
+	int part_fmt = 0; /* 0:unknown, 1:AHDI, 2:ICD/Supra */
 #endif
 
-  bh = bread (dev, 0, get_ptable_blocksize(dev));
-  if (!bh) {
-      if (warn_no_part) printk (" unable to read block 0 (partition table)\n");
-      return -1;
-  }
-
-  /* Verify this is an Atari rootsector: */
-  rs = (struct rootsector *) bh->b_data;
-  hd_size = hd->part[minor - 1].nr_sects;
-  if (!VALID_PARTITION(&rs->part[0], hd_size) &&
-      !VALID_PARTITION(&rs->part[1], hd_size) &&
-      !VALID_PARTITION(&rs->part[2], hd_size) &&
-      !VALID_PARTITION(&rs->part[3], hd_size)) {
-      /* if there's no valid primary partition, assume that no Atari
-	 format partition table (there's no reliable magic or the like
-	 :-() */
-      brelse(bh);
-      return 0;
-  }
-
-  pi = &rs->part[0];
-  printk (" AHDI");
-  for (; pi < &rs->part[4] && minor < m_lim; minor++, pi++)
-    {
-      if (pi->flg & 1)
-	/* active partition */
-	{
-	  if (memcmp (pi->id, "XGM", 3) == 0)
-	    /* extension partition */
-	    {
-	      struct rootsector *xrs;
-	      struct buffer_head *xbh;
-	      ulong partsect;
+	rs = (struct rootsector *) read_dev_sector(bdev, 0, &sect);
+	if (!rs)
+		return -1;
+
+	/* Verify this is an Atari rootsector: */
+	hd_size = hd->part[minor - 1].nr_sects;
+	if (!VALID_PARTITION(&rs->part[0], hd_size) &&
+	    !VALID_PARTITION(&rs->part[1], hd_size) &&
+	    !VALID_PARTITION(&rs->part[2], hd_size) &&
+	    !VALID_PARTITION(&rs->part[3], hd_size)) {
+		/*
+		 * if there's no valid primary partition, assume that no Atari
+		 * format partition table (there's no reliable magic or the like
+	         * :-()
+		 */
+		put_dev_sector(sect);
+		return 0;
+	}
 
+	pi = &rs->part[0];
+	printk (" AHDI");
+	for (; pi < &rs->part[4] && minor < m_lim; minor++, pi++) {
+		struct rootsector *xrs;
+		Sector sect2;
+		ulong partsect;
+
+		if ( !(pi->flg & 1) )
+			continue;
+		/* active partition */
+		if (memcmp (pi->id, "XGM", 3) != 0) {
+			/* we don't care about other id's */
+			add_gd_partition (hd, minor, be32_to_cpu(pi->st),
+					be32_to_cpu(pi->siz));
+			continue;
+		}
+		/* extension partition */
 #ifdef ICD_PARTS
-	      part_fmt = 1;
+		part_fmt = 1;
 #endif
-	      printk(" XGM<");
-	      partsect = extensect = be32_to_cpu(pi->st);
-	      while (1)
-		{
-		  xbh = bread (dev, partsect / 2, get_ptable_blocksize(dev));
-		  if (!xbh)
-		    {
-		      printk (" block %ld read failed\n", partsect);
-		      brelse(bh);
-		      return 0;
-		    }
-		  if (partsect & 1)
-		    xrs = (struct rootsector *) &xbh->b_data[512];
-		  else
-		    xrs = (struct rootsector *) &xbh->b_data[0];
-
-		  /* ++roman: sanity check: bit 0 of flg field must be set */
-		  if (!(xrs->part[0].flg & 1)) {
-		    printk( "\nFirst sub-partition in extended partition is not valid!\n" );
-		    break;
-		  }
+		printk(" XGM<");
+		partsect = extensect = be32_to_cpu(pi->st);
+		while (1) {
+			xrs = (struct rootsector *)read_dev_sector(bdev, partsect, &sect2);
+			if (!xrs) {
+				printk (" block %ld read failed\n", partsect);
+				put_dev_sector(sect);
+				return 0;
+			}
+
+			/* ++roman: sanity check: bit 0 of flg field must be set */
+			if (!(xrs->part[0].flg & 1)) {
+				printk( "\nFirst sub-partition in extended partition is not valid!\n" );
+				put_dev_sector(sect2);
+				break;
+			}
 
-		  add_gd_partition(hd, minor,
+			add_gd_partition(hd, minor,
 				   partsect + be32_to_cpu(xrs->part[0].st),
 				   be32_to_cpu(xrs->part[0].siz));
 
-		  if (!(xrs->part[1].flg & 1)) {
-		    /* end of linked partition list */
-		    brelse( xbh );
-		    break;
-		  }
-		  if (memcmp( xrs->part[1].id, "XGM", 3 ) != 0) {
-		    printk( "\nID of extended partition is not XGM!\n" );
-		    brelse( xbh );
-		    break;
-		  }
-
-		  partsect = be32_to_cpu(xrs->part[1].st) + extensect;
-		  brelse (xbh);
-		  minor++;
-		  if (minor >= m_lim) {
-		    printk( "\nMaximum number of partitions reached!\n" );
-		    break;
-		  }
+			if (!(xrs->part[1].flg & 1)) {
+				/* end of linked partition list */
+				put_dev_sector(sect2);
+				break;
+			}
+			if (memcmp( xrs->part[1].id, "XGM", 3 ) != 0) {
+				printk("\nID of extended partition is not XGM!\n");
+				put_dev_sector(sect2);
+				break;
+			}
+
+			partsect = be32_to_cpu(xrs->part[1].st) + extensect;
+			put_dev_sector(sect2);
+			minor++;
+			if (minor >= m_lim) {
+				printk( "\nMaximum number of partitions reached!\n" );
+				break;
+			}
 		}
-	      printk(" >");
-	    }
-	  else
-	    {
-	      /* we don't care about other id's */
-	      add_gd_partition (hd, minor, be32_to_cpu(pi->st),
-				be32_to_cpu(pi->siz));
-	    }
+		printk(" >");
 	}
-    }
 #ifdef ICD_PARTS
-  if ( part_fmt!=1 ) /* no extended partitions -> test ICD-format */
-  {
-    pi = &rs->icdpart[0];
-    /* sanity check: no ICD format if first partition invalid */
-    if (memcmp (pi->id, "GEM", 3) == 0 ||
-        memcmp (pi->id, "BGM", 3) == 0 ||
-        memcmp (pi->id, "LNX", 3) == 0 ||
-        memcmp (pi->id, "SWP", 3) == 0 ||
-        memcmp (pi->id, "RAW", 3) == 0 )
-    {
-      printk(" ICD<");
-      for (; pi < &rs->icdpart[8] && minor < m_lim; minor++, pi++)
-      {
-        /* accept only GEM,BGM,RAW,LNX,SWP partitions */
-        if (pi->flg & 1 && 
-            (memcmp (pi->id, "GEM", 3) == 0 ||
-             memcmp (pi->id, "BGM", 3) == 0 ||
-             memcmp (pi->id, "LNX", 3) == 0 ||
-             memcmp (pi->id, "SWP", 3) == 0 ||
-             memcmp (pi->id, "RAW", 3) == 0) )
-        {
-          part_fmt = 2;
-	  add_gd_partition (hd, minor, be32_to_cpu(pi->st),
-			    be32_to_cpu(pi->siz));
-        }
-      }
-      printk(" >");
-    }
-  }
+	if ( part_fmt!=1 ) { /* no extended partitions -> test ICD-format */
+		pi = &rs->icdpart[0];
+		/* sanity check: no ICD format if first partition invalid */
+		if (OK_id(pi->id)) {
+			printk(" ICD<");
+			for (; pi < &rs->icdpart[8] && minor < m_lim; minor++, pi++) {
+				/* accept only GEM,BGM,RAW,LNX,SWP partitions */
+				if (!((pi->flg & 1) && OK_id(pi->id)))
+					continue;
+				part_fmt = 2;
+				add_gd_partition (hd, minor,
+						be32_to_cpu(pi->st),
+						be32_to_cpu(pi->siz));
+			}
+			printk(" >");
+		}
+	}
 #endif
-  brelse (bh);
+	put_dev_sector(sect);
 
-  printk ("\n");
+	printk ("\n");
 
-  return 1;
+	return 1;
 }
 
diff -urN linux-2.4.11-pre2/fs/partitions/atari.h linux/fs/partitions/atari.h
--- linux-2.4.11-pre2/fs/partitions/atari.h	Sat Sep  4 13:09:36 1999
+++ linux/fs/partitions/atari.h	Mon Dec  3 23:15:40 2001
@@ -31,6 +31,6 @@
   u16 checksum;			/* checksum for bootable disks */
 } __attribute__((__packed__));
 
-int atari_partition (struct gendisk *hd, kdev_t dev,
+int atari_partition (struct gendisk *hd, struct block_device *bdev,
 		     unsigned long first_sector, int first_part_minor);
 
diff -urN linux-2.4.11-pre2/fs/partitions/check.c linux/fs/partitions/check.c
--- linux-2.4.11-pre2/fs/partitions/check.c	Mon Dec  3 23:15:30 2001
+++ linux/fs/partitions/check.c	Mon Dec  3 23:15:40 2001
@@ -38,7 +38,7 @@
 
 int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/
 
-static int (*check_part[])(struct gendisk *hd, kdev_t dev, unsigned long first_sect, int first_minor) = {
+static int (*check_part[])(struct gendisk *hd, struct block_device *bdev, unsigned long first_sect, int first_minor) = {
 #ifdef CONFIG_ACORN_PARTITION
 	acorn_partition,
 #endif
@@ -215,54 +215,12 @@
 #endif
 }
 
-unsigned int get_ptable_blocksize(kdev_t dev)
-{
-	int ret = 1024;
-
-	/*
-	 * See whether the low-level driver has given us a minumum blocksize.
-	 * If so, check to see whether it is larger than the default of 1024.
-	 */
-	if (!blksize_size[MAJOR(dev)])
-		return ret;
-
-	/*
-	 * Check for certain special power of two sizes that we allow.
-	 * With anything larger than 1024, we must force the blocksize up to
-	 * the natural blocksize for the device so that we don't have to try
-	 * and read partial sectors.  Anything smaller should be just fine.
-	 */
-
-	switch (blksize_size[MAJOR(dev)][MINOR(dev)]) {
-		case 2048:
-			ret = 2048;
-			break;
-		case 4096:
-			ret = 4096;
-			break;
-		case 8192:
-			ret = 8192;
-			break;
-		case 1024:
-		case 512:
-		case 256:
-		case 0:
-			/*
-			 * These are all OK.
-			 */
-			break;
-		default:
-			panic("Strange blocksize for partition table\n");
-	}
-
-	return ret;
-}
-
 static void check_partition(struct gendisk *hd, kdev_t dev, int first_part_minor)
 {
 	devfs_handle_t de = NULL;
 	static int first_time = 1;
 	unsigned long first_sector;
+	struct block_device *bdev;
 	char buf[64];
 	int i;
 
@@ -287,12 +245,23 @@
 		printk(KERN_INFO " /dev/%s:", buf + i);
 	else
 		printk(KERN_INFO " %s:", disk_name(hd, MINOR(dev), buf));
-	for (i = 0; check_part[i]; i++)
-		if (check_part[i](hd, dev, first_sector, first_part_minor))
+	bdev = bdget(kdev_t_to_nr(dev));
+	bdev->bd_inode->i_size = (loff_t)hd->part[MINOR(dev)].nr_sects << 9;
+	for (i = 0; check_part[i]; i++) {
+		int res;
+		res = check_part[i](hd, bdev, first_sector, first_part_minor);
+		if (res) {
+			if (res < 0 &&  warn_no_part)
+				printk(" unable to read partition table\n");
 			goto setup_devfs;
+		}
+	}
 
 	printk(" unknown partition table\n");
 setup_devfs:
+	invalidate_bdev(bdev, 1);
+	truncate_inode_pages(bdev->bd_inode->i_mapping, 0);
+	bdput(bdev);
 	i = first_part_minor - 1;
 	devfs_register_partitions (hd, i, hd->sizes ? 0 : 1);
 }
@@ -427,4 +396,27 @@
 			dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
 		blk_size[dev->major] = dev->sizes;
 	}
+}
+
+unsigned char *read_dev_sector(struct block_device *bdev, unsigned long n, Sector *p)
+{
+	struct address_space *mapping = bdev->bd_inode->i_mapping;
+	int sect = PAGE_CACHE_SIZE / 512;
+	struct page *page;
+
+	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))
+			goto fail;
+		if (PageError(page))
+			goto fail;
+		p->v = page;
+		return (unsigned char *)page_address(page) + 512 * (n % sect);
+fail:
+		page_cache_release(page);
+	}
+	p->v = NULL;
+	return NULL;
 }
diff -urN linux-2.4.11-pre2/fs/partitions/check.h linux/fs/partitions/check.h
--- linux-2.4.11-pre2/fs/partitions/check.h	Wed Feb 16 15:42:06 2000
+++ linux/fs/partitions/check.h	Mon Dec  3 23:15:40 2001
@@ -4,9 +4,13 @@
  */
 void add_gd_partition(struct gendisk *hd, int minor, int start, int size);
 
-/*
- * Get the default block size for this device
- */
-unsigned int get_ptable_blocksize(kdev_t dev);
+typedef struct {struct page *v;} Sector;
+
+unsigned char *read_dev_sector(struct block_device *, unsigned long, Sector *);
+
+static inline void put_dev_sector(Sector p)
+{
+	page_cache_release(p.v);
+}
 
 extern int warn_no_part;
diff -urN linux-2.4.11-pre2/fs/partitions/ibm.c linux/fs/partitions/ibm.c
--- linux-2.4.11-pre2/fs/partitions/ibm.c	Sat Sep 22 20:35:43 2001
+++ linux/fs/partitions/ibm.c	Mon Dec  3 23:15:40 2001
@@ -42,30 +42,6 @@
 			     [ibm_partition_none] = "(nonl)"
 };
 
-static int
-get_drive_geometry(int kdev,struct hd_geometry *geo) 
-{
-	struct block_device *bdev = bdget(kdev_t_to_nr(kdev));
-	int rc = blkdev_get(bdev, 0, 1, BDEV_FILE);
-        if ( rc == 0 ) {
-		rc = ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)geo);
-		blkdev_put(bdev, BDEV_FILE);
-	}
-	return rc;
-}
-
-static int
-get_drive_info(int kdev,dasd_information_t *info) 
-{
-	struct block_device *bdev = bdget(kdev_t_to_nr(kdev));
-	int rc = blkdev_get(bdev, 0, 1, BDEV_FILE);
-        if ( rc == 0 ) {
-		rc = ioctl_by_bdev(bdev, BIODASDINFO, (unsigned long)(info));
-		blkdev_put(bdev, BDEV_FILE);
-	}
-	return rc;
-}
-
 static ibm_partition_t
 get_partition_type ( char * type )
 {
@@ -89,10 +65,8 @@
 	       int offset,
 	       int size) {
 
-        add_gd_partition( hd, minor, 0,size);
-	add_gd_partition( hd, minor + 1, 
-			   offset * (blocksize >> 9),
-			   size-offset*(blocksize>>9));
+        add_gd_partition( hd, minor, 0, size);
+	add_gd_partition( hd, minor+1, offset*blocksize, size-offset*blocksize);
 }
 
 
@@ -119,10 +93,11 @@
 }
 
 int 
-ibm_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, int
-first_part_minor)
+ibm_partition(struct gendisk *hd, struct block_device *bdev,
+		unsigned long first_sector, int first_part_minor)
 {
-	struct buffer_head *bh, *buf;
+	Sector sect, sect2;
+	unsigned char *data;
 	ibm_partition_t partition_type;
 	char type[5] = {0,};
 	char name[7] = {0,};
@@ -133,40 +108,41 @@
 	format1_label_t f1;
 	volume_label_t vlabel;
 	dasd_information_t *info;
+	kdev_t dev = to_kdev_t(bdev->bd_dev);
 
-	if ( first_sector != 0 ) {
+	if ( first_sector != 0 )
 		BUG();
-	}
+
 	info = (struct dasd_information_t *)kmalloc(sizeof(dasd_information_t),
 						    GFP_KERNEL);
 	if ( info == NULL )
 		return 0;
-	if (get_drive_info (dev,info)) 
+	if (ioctl_by_bdev(bdev, BIODASDINFO, (unsigned long)(info)))
 		return 0;
 	geo = (struct hd_geometry *)kmalloc(sizeof(struct hd_geometry),
 					    GFP_KERNEL);
 	if ( geo == NULL )
 		return 0;
-	if (get_drive_geometry (dev,geo)) 
+	if (ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)geo);
 		return 0;
 	blocksize = hardsect_size[MAJOR(dev)][MINOR(dev)];
 	if ( blocksize <= 0 ) {
 		return 0;
 	}
+	blocksize >>= 9;
 	
-	set_blocksize(dev, blocksize);  /* OUCH !! */
-	if ( ( bh = bread( dev, info->label_block, blocksize) ) != NULL ) {
-		strncpy ( type,bh -> b_data + 0, 4);
-		if ((!info->FBA_layout) && (!strcmp(info->type,"ECKD"))) {
-		        
-		        strncpy ( name,bh -> b_data + 8, 6);
-		} else {
-		        strncpy ( name,bh -> b_data + 4, 6);		  
-		}
-		memcpy (&vlabel, bh->b_data, sizeof(volume_label_t));
-        } else {
+	data = read_dev_sector(bdev, inode->label_block*blocksize, &sect);
+	if (!data)
 		return 0;
+
+	strncpy (type, data, 4);
+	if ((!info->FBA_layout) && (!strcmp(info->type,"ECKD"))) {
+		strncpy ( name, data + 8, 6);
+	} else {
+		strncpy ( name, data + 4, 6);
 	}
+	memcpy (&vlabel, data, sizeof(volume_label_t));
+
 	EBCASC(type,4);
 	EBCASC(name,6);
 	
@@ -174,12 +150,12 @@
 	printk ( "%4s/%8s:",part_names[partition_type],name);
 	switch ( partition_type ) {
 	case ibm_partition_cms1:
-		if (* (((long *)bh->b_data) + 13) != 0) {
+		if (* ((long *)data + 13) != 0) {
 			/* disk is reserved minidisk */
-			long *label=(long*)bh->b_data;
-			blocksize = label[3];
+			long *label=(long*)data;
+			blocksize = label[3]>>9;
 			offset = label[13];
-			size = (label[7]-1)*(blocksize>>9); 
+			size = (label[7]-1)*blocksize; 
 			printk ("(MDSK)");
 		} else {
 			offset = (info->label_block + 1);
@@ -199,9 +175,10 @@
 		
 		/* get block number and read then first format1 label */
 		blk = cchhb2blk(&vlabel.vtoc, geo) + 1;
-		if ((buf = bread( dev, blk, blocksize)) != NULL) {
-		        memcpy (&f1, buf->b_data, sizeof(format1_label_t));
-			bforget(buf);
+		data = read_dev_sector(bdev, blk * blocksize, &sect2);
+		if (data) {
+		        memcpy (&f1, data, sizeof(format1_label_t));
+			put_dev_sector(sect2);
 		}
 		
 		while (f1.DS1FMTID == _ascebc['1']) {
@@ -211,14 +188,14 @@
 			
 			counter++;
 			add_gd_partition(hd, MINOR(dev) + counter, 
-					 offset * (blocksize >> 9),
-					 psize * (blocksize >> 9));
+					 offset * blocksize,
+					 psize * blocksize);
 			
 			blk++;
-			if ((buf = bread( dev, blk, blocksize)) != NULL) {
-			        memcpy (&f1, buf->b_data, 
-					sizeof(format1_label_t));
-				bforget(buf);
+			data = read_dev_sector(bdev, blk * blocksize, &sect2);
+			if (data) {
+			        memcpy (&f1, data, sizeof(format1_label_t));
+				put_dev_sector(sect2);
 			}
 		}
 		break;
@@ -228,6 +205,6 @@
 	}
 	
 	printk ( "\n" );
-	bforget(bh);
+	put_dev_sector(sect);
 	return 1;
 }
diff -urN linux-2.4.11-pre2/fs/partitions/ibm.h linux/fs/partitions/ibm.h
--- linux-2.4.11-pre2/fs/partitions/ibm.h	Fri Feb 16 16:02:37 2001
+++ linux/fs/partitions/ibm.h	Mon Dec  3 23:15:40 2001
@@ -1 +1 @@
-int ibm_partition(struct gendisk *, kdev_t, unsigned long, int);
+int ibm_partition(struct gendisk *, struct block_device *, unsigned long, int);
diff -urN linux-2.4.11-pre2/fs/partitions/ldm.c linux/fs/partitions/ldm.c
--- linux-2.4.11-pre2/fs/partitions/ldm.c	Fri Sep  7 09:28:38 2001
+++ linux/fs/partitions/ldm.c	Mon Dec  3 23:15:40 2001
@@ -178,10 +178,12 @@
  */
 static int create_data_partitions(struct gendisk *hd,
 		const unsigned long first_sector, int first_part_minor,
-		const kdev_t dev, const struct vmdb *vm,
-		const struct privhead *ph, const struct ldmdisk *dk)
+		struct block_device *bdev, const struct vmdb *vm,
+		const struct privhead *ph, const struct ldmdisk *dk,
+		unsigned long base)
 {
-	struct buffer_head *bh;
+	Sector  sect;
+	unsigned char *data;
 	struct vblk *vb;
 	int vblk;
 	int vsize;		/* VBLK size. */
@@ -192,14 +194,14 @@
 	if (!vb)
 		goto no_mem;
 	vsize   = vm->vblk_size;
-	if (vsize < 1 || vsize > LDM_BLOCKSIZE)
+	if (vsize < 1 || vsize > 512)
 		goto err_out;
-	perbuf  = LDM_BLOCKSIZE / vsize;
-	if (perbuf < 1 || LDM_BLOCKSIZE % vsize)
+	perbuf  = 512 / vsize;
+	if (perbuf < 1 || 512 % vsize)
 		goto err_out;
 					/* 512 == VMDB size */
-	lastbuf = (vm->last_vblk_seq - (512 / vsize)) / perbuf;
-	lastofs = (vm->last_vblk_seq - (512 / vsize)) % perbuf;
+	lastbuf = vm->last_vblk_seq / perbuf - 1;
+	lastofs = vm->last_vblk_seq % perbuf;
 	if (lastofs)
 		lastbuf++;
 	if (OFF_VBLK * LDM_BLOCKSIZE + vm->last_vblk_seq * vsize >
@@ -207,17 +209,18 @@
 		goto err_out;
 	printk(" <");
 	for (buffer = 0; buffer < lastbuf; buffer++) {
-		if (!(bh = bread(dev, buffer + OFF_VBLK, LDM_BLOCKSIZE)))
+		data = read_dev_sector(bdev, base + 2*OFF_VBLK + buffer, &sect);
+		if (!data)
 			goto read_err;
 		for (vblk = 0; vblk < perbuf; vblk++) {
 			u8 *block;
 			
 			if (lastofs && buffer == lastbuf - 1 && vblk >= lastofs)
 				break;
-			block = bh->b_data + vsize * vblk;
-			if (block + vsize > (u8*)bh->b_data + LDM_BLOCKSIZE)
+			block = data + vsize * vblk;
+			if (block + vsize > data + 512)
 				goto brelse_out;
-			if (parse_vblk(block, LDM_BLOCKSIZE, vb) != 1)
+			if (parse_vblk(block, vsize, vb) != 1)
 				continue;
 			if (vb->vblk_type != VBLK_PART)
 				continue;
@@ -229,7 +232,7 @@
 					vb->num_sectors) == 1)
 				first_part_minor++;
 		}
-		brelse(bh);
+		put_dev_sector(sect);
 	}
 	printk(" >\n");
 	err = 1;
@@ -237,7 +240,7 @@
 	kfree(vb);
 	return err;
 brelse_out:
-	brelse(bh);
+	put_dev_sector(sect);
 	goto err_out;
 no_mem:
 	printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
@@ -326,10 +329,12 @@
  *
  * Return 1 on success and -1 on error, in which case @dk is undefined.
  */
-static int get_disk_objid(const kdev_t dev, const struct vmdb *vm,
-		const struct privhead *ph, struct ldmdisk *dk)
+static int get_disk_objid(struct block_device *bdev, const struct vmdb *vm,
+		const struct privhead *ph, struct ldmdisk *dk,
+		unsigned long base)
 {
-	struct buffer_head *bh;
+	Sector sect;
+	unsigned char *data;
 	u8 *disk_id;
 	int vblk;
 	int vsize;		/* VBLK size. */
@@ -340,21 +345,22 @@
 	if (!disk_id)
 		goto no_mem;
 	vsize   = vm->vblk_size;
-	if (vsize < 1 || vsize > LDM_BLOCKSIZE)
+	if (vsize < 1 || vsize > 512)
 		goto err_out;
-	perbuf  = LDM_BLOCKSIZE / vsize;
-	if (perbuf < 1 || LDM_BLOCKSIZE % vsize)
+	perbuf  = 512 / vsize;
+	if (perbuf < 1 || 512 % vsize)
 		goto err_out;
 					/* 512 == VMDB size */
-	lastbuf = (vm->last_vblk_seq - (512 / vsize)) / perbuf;
-	lastofs = (vm->last_vblk_seq - (512 / vsize)) % perbuf;
+	lastbuf = vm->last_vblk_seq / perbuf - 1;
+	lastofs = vm->last_vblk_seq % perbuf;
 	if (lastofs)
 		lastbuf++;
 	if (OFF_VBLK * LDM_BLOCKSIZE + vm->last_vblk_seq * vsize >
 			ph->config_size * 512)
 		goto err_out;
 	for (buffer = 0; buffer < lastbuf; buffer++) {
-		if (!(bh = bread(dev, buffer + OFF_VBLK, LDM_BLOCKSIZE)))
+		data = read_dev_sector(bdev, base + 2*OFF_VBLK + buffer, &sect);
+		if (!data)
 			goto read_err;
 		for (vblk = 0; vblk < perbuf; vblk++) {
 			int rel_objid, rel_name, delta;
@@ -362,20 +368,19 @@
 
 			if (lastofs && buffer == lastbuf - 1 && vblk >= lastofs)
 				break;
-			block = bh->b_data + vblk * vsize;
+			block = data + vblk * vsize;
 			delta = vblk * vsize + 0x18;
-			if (delta >= LDM_BLOCKSIZE)
+			if (delta >= 512)
 				goto brelse_out;
 			if (block[0x13] != VBLK_DISK)
 				continue;
 			/* Calculate relative offsets. */
 			rel_objid = 1 + block[0x18];
-			if (delta + rel_objid >= LDM_BLOCKSIZE)
+			if (delta + rel_objid >= 512)
 				goto brelse_out;
 			rel_name  = 1 + block[0x18 + rel_objid] + rel_objid;
-			if (delta + rel_name >= LDM_BLOCKSIZE ||
-			    delta + rel_name + block[0x18 + rel_name] >=
-					LDM_BLOCKSIZE)
+			if (delta + rel_name >= 512 ||
+			    delta + rel_name + block[0x18 + rel_name] >= 512)
 				goto brelse_out;
 			err = get_vstr(block + 0x18 + rel_name, disk_id,
 					DISK_ID_SIZE);
@@ -383,7 +388,7 @@
 				goto brelse_out;
 			if (!strncmp(disk_id, ph->disk_id, DISK_ID_SIZE)) {
 				dk->obj_id = get_vnum(block + 0x18, &err);
-				brelse(bh);
+				put_dev_sector(sect);
 				if (err)
 					goto out;
 				strncpy(dk->disk_id, ph->disk_id,
@@ -393,14 +398,14 @@
 				goto out;
 			}
 		}
-		brelse(bh);
+		put_dev_sector(sect);
 	}
 	err = -1;
 out:
 	kfree(disk_id);
 	return err;
 brelse_out:
-	brelse(bh);
+	put_dev_sector(sect);
 	goto err_out;
 no_mem:
 	printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
@@ -457,17 +462,19 @@
  *
  * Return 1 on success and -1 on error, in which case @vm is undefined.
  */
-static int validate_vmdb(const kdev_t dev, struct vmdb *vm)
+static int validate_vmdb(struct block_device *bdev, struct vmdb *vm, unsigned long base)
 {
-	struct buffer_head *bh;
+	Sector sect;
+	unsigned char *data;
 	int ret;
 
-	if (!(bh = bread(dev, OFF_VMDB, LDM_BLOCKSIZE))) {
+	data = read_dev_sector(bdev, base + OFF_VMDB * 2 + 1, &sect);
+	if (!data) {
 		printk(LDM_CRIT "Disk read failed in validate_vmdb.\n");
 		return -1;
 	}
-	ret = parse_vmdb(bh->b_data + 0x200, vm);
-	brelse(bh);
+	ret = parse_vmdb(data, vm);
+	put_dev_sector(sect);
 	return ret;
 }
 
@@ -553,9 +560,12 @@
  *
  * Return 1 on success and -1 on error, in which case @toc1 is undefined.
  */
-static int validate_tocblocks(const kdev_t devdb, struct tocblock *toc1)
+static int validate_tocblocks(struct block_device *bdev,
+			struct tocblock *toc1,
+			unsigned long base)
 {
-	struct buffer_head *bh;
+	Sector sect;
+	unsigned char *data;
 	struct tocblock *toc2 = NULL, *toc3 = NULL, *toc4 = NULL;
 	int err;
 
@@ -569,39 +579,43 @@
 	if (!toc4)
 		goto no_mem;
 	/* Read and parse first toc. */
-	if (!(bh = bread(devdb, OFF_TOCBLOCK1, LDM_BLOCKSIZE))) {
+	data = read_dev_sector(bdev, base + OFF_TOCBLOCK1 * 2 + 1, &sect);
+	if (!data) {
 		printk(LDM_CRIT "Disk read 1 failed in validate_tocblocks.\n");
 		goto err_out;
 	}
-	err = parse_tocblock(bh->b_data + 0x0200, toc1);
-	brelse(bh);
+	err = parse_tocblock(data, toc1);
+	put_dev_sector(sect);
 	if (err != 1)
 		goto out;
 	/* Read and parse second toc. */
-	if (!(bh = bread(devdb, OFF_TOCBLOCK2, LDM_BLOCKSIZE))) {
+	data = read_dev_sector(bdev, base + OFF_TOCBLOCK2 * 2, &sect);
+	if (!data) {
 		printk(LDM_CRIT "Disk read 2 failed in validate_tocblocks.\n");
 		goto err_out;
 	}
-	err = parse_tocblock(bh->b_data, toc2);
-	brelse(bh);
+	err = parse_tocblock(data, toc2);
+	put_dev_sector(sect);
 	if (err != 1)
 		goto out;
 	/* Read and parse third toc. */
-	if (!(bh = bread(devdb, OFF_TOCBLOCK3, LDM_BLOCKSIZE))) {
+	data = read_dev_sector(bdev, base + OFF_TOCBLOCK3 * 2 + 1, &sect);
+	if (!data) {
 		printk(LDM_CRIT "Disk read 3 failed in validate_tocblocks.\n");
 		goto err_out;
 	}
-	err = parse_tocblock(bh->b_data + 0x0200, toc3);
-	brelse(bh);
+	err = parse_tocblock(data, toc3);
+	put_dev_sector(sect);
 	if (err != 1)
 		goto out;
 	/* Read and parse fourth toc. */
-	if (!(bh = bread(devdb, OFF_TOCBLOCK4, LDM_BLOCKSIZE))) {
+	data = read_dev_sector(bdev, base + OFF_TOCBLOCK4 * 2, &sect);
+	if (!data) {
 		printk(LDM_CRIT "Disk read 4 failed in validate_tocblocks.\n");
 		goto err_out;
 	}
-	err = parse_tocblock(bh->b_data, toc4);
-	brelse(bh);
+	err = parse_tocblock(data, toc4);
+	put_dev_sector(sect);
 	if (err != 1)
 		goto out;
 	/* Compare all tocs. */
@@ -665,9 +679,12 @@
  *
  * Return 1 on succes and -1 on error.
  */
-static int validate_privheads(const kdev_t dev, const struct privhead *ph1)
+static int validate_privheads(struct block_device *bdev,
+			      const struct privhead *ph1,
+			      unsigned long base)
 {
-	struct buffer_head *bh;
+	Sector sect;
+	unsigned char *data;
 	struct privhead *ph2 = NULL, *ph3 = NULL;
 	int err;
 
@@ -677,20 +694,22 @@
 	ph3 = (struct privhead*)kmalloc(sizeof(*ph3), GFP_KERNEL);
 	if (!ph3)
 		goto no_mem;
-	if (!(bh = bread(dev, OFF_PRIVHEAD2, LDM_BLOCKSIZE))) {
+	data = read_dev_sector(bdev, base + OFF_PRIVHEAD2 * 2, &sect);
+	if (!data) {
 		printk(LDM_CRIT "Disk read 1 failed in validate_privheads.\n");
 		goto err_out;
 	}
-	err = parse_privhead(bh->b_data, ph2);
-	brelse(bh);
+	err = parse_privhead(data, ph2);
+	put_dev_sector(sect);
 	if (err != 1)
 		goto out;
-	if (!(bh = bread(dev, OFF_PRIVHEAD3, LDM_BLOCKSIZE))) {
+	data = read_dev_sector(bdev, base + OFF_PRIVHEAD3 * 2 + 1, &sect);
+	if (!data) {
 		printk(LDM_CRIT "Disk read 2 failed in validate_privheads.\n");
 		goto err_out;
 	}
-	err = parse_privhead(bh->b_data + 0x0200, ph3);
-	brelse(bh);
+	err = parse_privhead(data, ph3);
+	put_dev_sector(sect);
 	if (err != 1)
 		goto out;
 	err = compare_privheads(ph1, ph2);
@@ -807,27 +826,29 @@
  *
  * Return 1 on succes, 0 if device is not a dynamic disk and -1 on error.
  */
-static int create_db_partition(struct gendisk *hd, const kdev_t dev,
+static int create_db_partition(struct gendisk *hd, struct block_device *bdev,
 		const unsigned long first_sector, const int first_part_minor,
 		struct privhead *ph)
 {
-	struct buffer_head *bh;
+	Sector sect;
+	unsigned char *data;
 	int err;
 
-	if (!(bh = bread(dev, OFF_PRIVHEAD1, LDM_BLOCKSIZE))) {
+	data = read_dev_sector(bdev, OFF_PRIVHEAD1*2, &sect);
+	if (!data) {
 		printk(LDM_CRIT __FUNCTION__ "(): Device read failed.\n");
 		return -1;
 	}
-	if (BE64(bh->b_data) != MAGIC_PRIVHEAD) {
+	if (BE64(data) != MAGIC_PRIVHEAD) {
 		ldm_debug("Cannot find PRIVHEAD structure. Not a dynamic disk "
 				"or corrupt LDM database.\n");
 		return 0;
 	}
-	err = parse_privhead(bh->b_data, ph);
+	err = parse_privhead(data, ph);
 	if (err == 1)
 		err = create_partition(hd, first_part_minor, first_sector +
 				ph->config_start, ph->config_size);
-	brelse(bh);
+	put_dev_sector(sect);
 	return err;
 }
 
@@ -842,23 +863,23 @@
  *
  * Return 1 if @dev is a dynamic disk, 0 if not and -1 on error.
  */
-static int validate_partition_table(const kdev_t dev)
+static int validate_partition_table(struct block_device *bdev)
 {
-	struct buffer_head *bh;
+	Sector sect;
+	unsigned char *data;
 	struct partition *p;
 	int i, nr_sfs;
 
-	if (!(bh = bread(dev, 0, LDM_BLOCKSIZE))) {
-		if (warn_no_part)
-			printk(LDM_ERR "Unable to read partition table.\n");
+	data = read_dev_sector(bdev, 0, &sect);
+	if (!data)
 		return -1;
-	}
-	if (*(u16*)(bh->b_data + 0x01FE) != cpu_to_le16(MSDOS_LABEL_MAGIC)) {
+
+	if (*(u16*)(data + 0x01FE) != cpu_to_le16(MSDOS_LABEL_MAGIC)) {
 		ldm_debug("No MS-DOS partition found.\n");
 		goto no_msdos_partition;
 	}
 	nr_sfs = 0;
-	p = (struct partition*)(bh->b_data + 0x01BE);
+	p = (struct partition*)(data + 0x01BE);
 	for (i = 0; i < 4; i++) {
 		if (!SYS_IND(p+i) || SYS_IND(p+i) == WIN2K_EXTENDED_PARTITION)
 			continue;
@@ -871,12 +892,12 @@
 	if (!nr_sfs)
 		goto not_dynamic_disk;
 	ldm_debug("Parsed partition table successfully.\n");
-	brelse(bh);
+	put_dev_sector(sect);
 	return 1;
 not_dynamic_disk:
 	ldm_debug("Found basic MS-DOS partition, not a dynamic disk.\n");
 no_msdos_partition:
-	brelse(bh);
+	put_dev_sector(sect);
 	return 0;
 }
 
@@ -904,67 +925,54 @@
  *	 0 if @dev is not a dynamic disk,
  *	-1 if an error occured.
  */
-int ldm_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector,
-		int first_part_minor)
+int ldm_partition(struct gendisk *hd, struct block_device *bdev,
+		unsigned long first_sector, int first_part_minor)
 {
-	kdev_t devdb;
 	struct privhead *ph  = NULL;
 	struct tocblock *toc = NULL;
 	struct vmdb     *vm  = NULL;
 	struct ldmdisk  *dk  = NULL;
+	unsigned long db_first;
 	int err;
 
 	if (!hd)
 		return 0;
-	err = (int)get_ptable_blocksize(dev);
-	if (err != LDM_BLOCKSIZE) {	/* 1024 bytes */
-		ldm_debug("Expected a blocksize of %d bytes, got %d instead.\n",
-				LDM_BLOCKSIZE, get_ptable_blocksize(dev));
-		return 0;
-	}
-	err = get_hardsect_size(dev); 
-	if (err != 512) {
-		ldm_debug("Expected a sector size of %d bytes, got %d "
-				"instead.\n", 512, get_hardsect_size(dev));
-		return 0;
-	}
 	/* Check the partition table. */
-	err = validate_partition_table(dev);
+	err = validate_partition_table(bdev);
 	if (err != 1)
 		return err;
 	if (!(ph = (struct privhead*)kmalloc(sizeof(*ph), GFP_KERNEL)))
 		goto no_mem;
 	/* Create the LDM database device. */
-	err = create_db_partition(hd, dev, first_sector, first_part_minor, ph);
+	err = create_db_partition(hd, bdev, first_sector, first_part_minor, ph);
 	if (err != 1)
 		goto out;
-	/* For convenience, work with the LDM database device from now on. */
-	devdb = MKDEV(MAJOR(dev), first_part_minor);
+	db_first = hd->part[first_part_minor].start_sect;
 	/* Check the backup privheads. */
-	err = validate_privheads(devdb, ph);
+	err = validate_privheads(bdev, ph, db_first);
 	if (err != 1)
 		goto out;
 	/* Check the table of contents and its backups. */
 	if (!(toc = (struct tocblock*)kmalloc(sizeof(*toc), GFP_KERNEL)))
 		goto no_mem;
-	err = validate_tocblocks(devdb, toc);
+	err = validate_tocblocks(bdev, toc, db_first);
 	if (err != 1)
 		goto out;
 	/* Check the vmdb. */
 	if (!(vm = (struct vmdb*)kmalloc(sizeof(*vm), GFP_KERNEL)))
 		goto no_mem;
-	err = validate_vmdb(devdb, vm);
+	err = validate_vmdb(bdev, vm, db_first);
 	if (err != 1)
 		goto out;
 	/* Find the object id for @dev in the LDM database. */
 	if (!(dk = (struct ldmdisk*)kmalloc(sizeof(*dk), GFP_KERNEL)))
 		goto no_mem;
-	err = get_disk_objid(devdb, vm, ph, dk);
+	err = get_disk_objid(bdev, vm, ph, dk, db_first);
 	if (err != 1)
 		goto out;
 	/* Finally, create the data partition devices. */
 	err = create_data_partitions(hd, first_sector, first_part_minor +
-			LDM_FIRST_PART_OFFSET, devdb, vm, ph, dk);
+			LDM_FIRST_PART_OFFSET, bdev, vm, ph, dk, db_first);
 	if (err == 1)
 		ldm_debug("Parsed LDM database successfully.\n");
 out:
diff -urN linux-2.4.11-pre2/fs/partitions/ldm.h linux/fs/partitions/ldm.h
--- linux-2.4.11-pre2/fs/partitions/ldm.h	Sun Sep 23 10:32:55 2001
+++ linux/fs/partitions/ldm.h	Mon Dec  3 23:15:40 2001
@@ -144,8 +144,8 @@
 	u64	num_sectors;
 };
 
-int ldm_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector,
-		int first_part_minor);
+int ldm_partition(struct gendisk *hd, struct block_device *bdev,
+		unsigned long first_sector, int first_part_minor);
 
 #endif /* _FS_PT_LDM_H_ */
 
diff -urN linux-2.4.11-pre2/fs/partitions/mac.c linux/fs/partitions/mac.c
--- linux-2.4.11-pre2/fs/partitions/mac.c	Sun Sep 17 09:51:57 2000
+++ linux/fs/partitions/mac.c	Mon Dec  3 23:15:40 2001
@@ -20,7 +20,7 @@
 #include "check.h"
 #include "mac.h"
 
-#ifdef CONFIG_PPC
+#ifdef CONFIG_ALL_PPC
 extern void note_bootable_part(kdev_t dev, int part, int goodness);
 #endif
 
@@ -36,69 +36,54 @@
 		stg[i] = 0;
 }
 
-int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec, int first_part_minor)
+int mac_partition(struct gendisk *hd, struct block_device *bdev,
+		unsigned long fsec, int first_part_minor)
 {
-	struct buffer_head *bh;
+	Sector sect;
+	unsigned char *data;
 	int blk, blocks_in_map;
-	int dev_bsize, dev_pos, pos;
 	unsigned secsize;
-#ifdef CONFIG_PPC
+#ifdef CONFIG_ALL_PPC
 	int found_root = 0;
 	int found_root_goodness = 0;
 #endif
 	struct mac_partition *part;
 	struct mac_driver_desc *md;
 
-	dev_bsize = get_ptable_blocksize(dev);
-	dev_pos = 0;
 	/* Get 0th block and look at the first partition map entry. */
-	if ((bh = bread(dev, 0, dev_bsize)) == 0) {
-	    printk("%s: error reading partition table\n",
-		   kdevname(dev));
-	    return -1;
-	}
-	md = (struct mac_driver_desc *) bh->b_data;
+	md = (struct mac_driver_desc *) read_dev_sector(bdev, 0, &sect);
+	if (!md)
+		return -1;
 	if (be16_to_cpu(md->signature) != MAC_DRIVER_MAGIC) {
-		brelse(bh);
+		put_dev_sector(sect);
 		return 0;
 	}
 	secsize = be16_to_cpu(md->block_size);
-	if (secsize >= dev_bsize) {
-		brelse(bh);
-		dev_pos = secsize;
-		if ((bh = bread(dev, secsize/dev_bsize, dev_bsize)) == 0) {
-			printk("%s: error reading Mac partition table\n",
-			       kdevname(dev));
-			return -1;
-		}
-	}
-	part = (struct mac_partition *) (bh->b_data + secsize - dev_pos);
+	put_dev_sector(sect);
+	data = read_dev_sector(bdev, secsize/512, &sect);
+	if (!data)
+		return -1;
+	part = (struct mac_partition *) (data + secsize%512);
 	if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC) {
-		brelse(bh);
+		put_dev_sector(sect);
 		return 0;		/* not a MacOS disk */
 	}
 	printk(" [mac]");
 	blocks_in_map = be32_to_cpu(part->map_count);
 	for (blk = 1; blk <= blocks_in_map; ++blk) {
-		pos = blk * secsize;
-		if (pos >= dev_pos + dev_bsize) {
-			brelse(bh);
-			dev_pos = pos;
-			if ((bh = bread(dev, pos/dev_bsize, dev_bsize)) == 0) {
-				printk("%s: error reading partition table\n",
-				       kdevname(dev));
-				return -1;
-			}
-		}
-		part = (struct mac_partition *) (bh->b_data + pos - dev_pos);
+		int pos = blk * secsize;
+		put_dev_sector(sect);
+		data = read_dev_sector(bdev, pos/512, &sect);
+		if (!data)
+			return -1;
+		part = (struct mac_partition *) (data + pos%512);
 		if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)
 			break;
-		blocks_in_map = be32_to_cpu(part->map_count);
 		add_gd_partition(hd, first_part_minor,
 			fsec + be32_to_cpu(part->start_block) * (secsize/512),
 			be32_to_cpu(part->block_count) * (secsize/512));
 
-#ifdef CONFIG_PPC
+#ifdef CONFIG_ALL_PPC
 		/*
 		 * If this is the first bootable partition, tell the
 		 * setup code, in case it wants to make this the root.
@@ -139,15 +124,17 @@
 				found_root_goodness = goodness;
 			}
 		}
-#endif /* CONFIG_PPC */
+#endif /* CONFIG_ALL_PPC */
 
 		++first_part_minor;
 	}
-#ifdef CONFIG_PPC
+#ifdef CONFIG_ALL_PPC
 	if (found_root_goodness)
-		note_bootable_part(dev, found_root, found_root_goodness);
+		note_bootable_part(to_kdev_t(bdev->bd_dev),
+					found_root, found_root_goodness);
 #endif
-	brelse(bh);
+
+	put_dev_sector(sect);
 	printk("\n");
 	return 1;
 }
diff -urN linux-2.4.11-pre2/fs/partitions/mac.h linux/fs/partitions/mac.h
--- linux-2.4.11-pre2/fs/partitions/mac.h	Thu Aug 12 12:26:06 1999
+++ linux/fs/partitions/mac.h	Mon Dec  3 23:15:40 2001
@@ -41,4 +41,4 @@
     /* ... more stuff */
 };
 
-int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec, int first_part_minor);
+int mac_partition(struct gendisk *hd, struct block_device *bdev, unsigned long fsec, int first_part_minor);
diff -urN linux-2.4.11-pre2/fs/partitions/msdos.c linux/fs/partitions/msdos.c
--- linux-2.4.11-pre2/fs/partitions/msdos.c	Sat Jul 28 12:50:13 2001
+++ linux/fs/partitions/msdos.c	Mon Dec  3 23:15:40 2001
@@ -40,8 +40,6 @@
 extern void md_autodetect_dev(kdev_t dev);
 #endif
 
-static int current_minor;
-
 /*
  * Many architectures don't like unaligned accesses, which is
  * frequently the case with the nr_sects and start_sect partition
@@ -88,7 +86,8 @@
 #define MSDOS_LABEL_MAGIC2	0xAA
 
 static inline int
-msdos_magic_present(unsigned char *p) {
+msdos_magic_present(unsigned char *p)
+{
 	return (p[0] == MSDOS_LABEL_MAGIC1 && p[1] == MSDOS_LABEL_MAGIC2);
 }
 
@@ -103,35 +102,38 @@
  * only for the actual data partitions.
  */
 
-static void extended_partition(struct gendisk *hd, kdev_t dev)
+static void extended_partition(struct gendisk *hd, struct block_device *bdev,
+				int minor, int *current_minor)
 {
-	struct buffer_head *bh;
 	struct partition *p;
+	Sector sect;
+	unsigned char *data;
 	unsigned long first_sector, first_size, this_sector, this_size;
 	int mask = (1 << hd->minor_shift) - 1;
-	int sector_size = get_hardsect_size(dev) / 512;
+	int sector_size = get_hardsect_size(to_kdev_t(bdev->bd_dev)) / 512;
 	int loopct = 0;		/* number of links followed
 				   without finding a data partition */
 	int i;
 
-	first_sector = hd->part[MINOR(dev)].start_sect;
-	first_size = hd->part[MINOR(dev)].nr_sects;
+	first_sector = hd->part[minor].start_sect;
+	first_size = hd->part[minor].nr_sects;
 	this_sector = first_sector;
 
 	while (1) {
 		if (++loopct > 100)
 			return;
-		if ((current_minor & mask) == 0)
+		if ((*current_minor & mask) == 0)
 			return;
-		if (!(bh = bread(dev,0,get_ptable_blocksize(dev))))
+		data = read_dev_sector(bdev, this_sector, &sect);
+		if (!data)
 			return;
 
-		if (!msdos_magic_present(bh->b_data + 510))
-			goto done;
+		if (!msdos_magic_present(data + 510))
+			goto done; 
 
-		p = (struct partition *) (bh->b_data + 0x1be);
+		p = (struct partition *) (data + 0x1be);
 
-		this_size = hd->part[MINOR(dev)].nr_sects;
+		this_size = hd->part[minor].nr_sects;
 
 		/*
 		 * Usually, the first entry is the real data partition,
@@ -146,30 +148,34 @@
 		 * First process the data partition(s)
 		 */
 		for (i=0; i<4; i++, p++) {
+			unsigned long offs, size, next;
 			if (!NR_SECTS(p) || is_extended_partition(p))
 				continue;
 
 			/* Check the 3rd and 4th entries -
 			   these sometimes contain random garbage */
-			if (i >= 2
-				&& START_SECT(p) + NR_SECTS(p) > this_size
-				&& (this_sector + START_SECT(p) < first_sector ||
-				    this_sector + START_SECT(p) + NR_SECTS(p) >
-				     first_sector + first_size))
-				continue;
+			offs = START_SECT(p)*sector_size;
+			size = NR_SECTS(p)*sector_size;
+			next = this_sector + offs;
+			if (i >= 2) {
+				if (offs + size > this_size)
+					continue;
+				if (next < first_sector)
+					continue;
+				if (next + size > first_sector + first_size)
+					continue;
+			}
 
-			add_gd_partition(hd, current_minor,
-					 this_sector+START_SECT(p)*sector_size,
-					 NR_SECTS(p)*sector_size);
+			add_gd_partition(hd, *current_minor, next, size);
 #if CONFIG_BLK_DEV_MD
 			if (SYS_IND(p) == LINUX_RAID_PARTITION) {
-			    md_autodetect_dev(MKDEV(hd->major,current_minor));
+			    md_autodetect_dev(MKDEV(hd->major,*current_minor));
 			}
 #endif
 
-			current_minor++;
+			(*current_minor)++;
 			loopct = 0;
-			if ((current_minor & mask) == 0)
+			if ((*current_minor & mask) == 0)
 				goto done;
 		}
 		/*
@@ -184,61 +190,52 @@
 		 */
 		p -= 4;
 		for (i=0; i<4; i++, p++)
-			if(NR_SECTS(p) && is_extended_partition(p))
+			if (NR_SECTS(p) && is_extended_partition(p))
 				break;
 		if (i == 4)
 			goto done;	 /* nothing left to do */
 
-		hd->part[current_minor].nr_sects = NR_SECTS(p) * sector_size; /* JSt */
-		hd->part[current_minor].start_sect = first_sector + START_SECT(p) * sector_size;
 		this_sector = first_sector + START_SECT(p) * sector_size;
-		dev = MKDEV(hd->major, current_minor);
-
-		/* Use bforget(), as we have changed the disk geometry */
-		bforget(bh);
+		minor = *current_minor;
+		put_dev_sector(sect);
 	}
 done:
-	bforget(bh);
+	put_dev_sector(sect);
 }
 
-static inline struct buffer_head *
-get_partition_table_block(struct gendisk *hd, int minor, int blocknr) {
-	kdev_t dev = MKDEV(hd->major, minor);
-	return bread(dev, blocknr, get_ptable_blocksize(dev));
-}
-
-#ifdef CONFIG_SOLARIS_X86_PARTITION
-
 /* james@bpgc.com: Solaris has a nasty indicator: 0x82 which also
    indicates linux swap.  Be careful before believing this is Solaris. */
 
 static void
-solaris_x86_partition(struct gendisk *hd, int minor) {
-	long offset = hd->part[minor].start_sect;
+solaris_x86_partition(struct gendisk *hd, struct block_device *bdev,
+		int minor, int *current_minor)
+{
 
-	struct buffer_head *bh;
+#ifdef CONFIG_SOLARIS_X86_PARTITION
+	long offset = hd->part[minor].start_sect;
+	Sector sect;
 	struct solaris_x86_vtoc *v;
 	struct solaris_x86_slice *s;
 	int mask = (1 << hd->minor_shift) - 1;
 	int i;
 	char buf[40];
 
-	if(!(bh = get_partition_table_block(hd, minor, 0)))
+	v = (struct solaris_x86_vtoc *)read_dev_sector(bdev, offset+1, &sect);
+	if (!v)
 		return;
-	v = (struct solaris_x86_vtoc *)(bh->b_data + 512);
-	if(le32_to_cpu(v->v_sanity) != SOLARIS_X86_VTOC_SANE) {
-		brelse(bh);
+	if (le32_to_cpu(v->v_sanity) != SOLARIS_X86_VTOC_SANE) {
+		put_dev_sector(sect);
 		return;
 	}
 	printk(" %s: <solaris:", partition_name(hd, minor, buf));
-	if(le32_to_cpu(v->v_version) != 1) {
+	if (le32_to_cpu(v->v_version) != 1) {
 		printk("  cannot handle version %d vtoc>\n",
 			le32_to_cpu(v->v_version));
-		brelse(bh);
+		put_dev_sector(sect);
 		return;
 	}
-	for(i=0; i<SOLARIS_X86_NUMSLICE; i++) {
-		if ((current_minor & mask) == 0)
+	for (i=0; i<SOLARIS_X86_NUMSLICE; i++) {
+		if ((*current_minor & mask) == 0)
 			break;
 		s = &v->v_slice[i];
 
@@ -249,23 +246,25 @@
 		 * one but add_gd_partition starts relative to sector
 		 * zero of the disk.  Therefore, must add the offset
 		 * of the current partition */
-		add_gd_partition(hd, current_minor, le32_to_cpu(s->s_start)+offset,
+		add_gd_partition(hd, *current_minor,
+				 le32_to_cpu(s->s_start)+offset,
 				 le32_to_cpu(s->s_size));
-		current_minor++;
+		(*current_minor)++;
 	}
-	brelse(bh);
+	put_dev_sector(sect);
 	printk(" >\n");
-}
 #endif
+}
 
 #ifdef CONFIG_BSD_DISKLABEL
 static void
-check_and_add_bsd_partition(struct gendisk *hd,
-			    struct bsd_partition *bsd_p, int minor) {
+check_and_add_bsd_partition(struct gendisk *hd, struct bsd_partition *bsd_p,
+	int minor, int *current_minor)
+{
 	struct hd_struct *lin_p;
 		/* check relative position of partitions.  */
 	for (lin_p = hd->part + 1 + minor;
-	     lin_p - hd->part - minor < current_minor; lin_p++) {
+	     lin_p - hd->part - minor < *current_minor; lin_p++) {
 			/* no relationship -> try again */
 		if (lin_p->start_sect + lin_p->nr_sects <= le32_to_cpu(bsd_p->p_offset) ||
 		    lin_p->start_sect >= le32_to_cpu(bsd_p->p_offset) + le32_to_cpu(bsd_p->p_size))
@@ -297,232 +296,290 @@
 	} /* if the bsd partition is not currently known to linux, we end
 	   * up here 
 	   */
-	add_gd_partition(hd, current_minor, le32_to_cpu(bsd_p->p_offset),
+	add_gd_partition(hd, *current_minor, le32_to_cpu(bsd_p->p_offset),
 			 le32_to_cpu(bsd_p->p_size));
-	current_minor++;
+	(*current_minor)++;
 }
 
 /* 
  * Create devices for BSD partitions listed in a disklabel, under a
  * dos-like partition. See extended_partition() for more information.
  */
-static void bsd_disklabel_partition(struct gendisk *hd, int minor, int type) {
-	struct buffer_head *bh;
+static void do_bsd_partition(struct gendisk *hd, struct block_device *bdev,
+	int minor, int *current_minor, char *name, int max_partitions)
+{
+	long offset = hd->part[minor].start_sect;
+	Sector sect;
 	struct bsd_disklabel *l;
 	struct bsd_partition *p;
-	int max_partitions;
 	int mask = (1 << hd->minor_shift) - 1;
 	char buf[40];
 
-	if (!(bh = get_partition_table_block(hd, minor, 0)))
+	l = (struct bsd_disklabel *)read_dev_sector(bdev, offset+1, &sect);
+	if (!l)
 		return;
-	l = (struct bsd_disklabel *) (bh->b_data+512);
 	if (le32_to_cpu(l->d_magic) != BSD_DISKMAGIC) {
-		brelse(bh);
+		put_dev_sector(sect);
 		return;
 	}
-	printk(" %s:", partition_name(hd, minor, buf));
-	printk((type == OPENBSD_PARTITION) ? " <openbsd:" :
-	       (type == NETBSD_PARTITION) ? " <netbsd:" : " <bsd:");
+	printk(" %s: <%s", partition_name(hd, minor, buf), name);
 
-	max_partitions = ((type == OPENBSD_PARTITION) ? OPENBSD_MAXPARTITIONS
-			                              : BSD_MAXPARTITIONS);
 	if (le16_to_cpu(l->d_npartitions) < max_partitions)
 		max_partitions = le16_to_cpu(l->d_npartitions);
 	for (p = l->d_partitions; p - l->d_partitions <  max_partitions; p++) {
-		if ((current_minor & mask) == 0)
+		if ((*current_minor & mask) == 0)
 			break;
-
-		if (p->p_fstype != BSD_FS_UNUSED) 
-			check_and_add_bsd_partition(hd, p, minor);
+		if (p->p_fstype == BSD_FS_UNUSED) 
+			continue;
+		check_and_add_bsd_partition(hd, p, minor, current_minor);
 	}
+	put_dev_sector(sect);
+	printk(" >\n");
+}
+#endif
 
-	/* Use bforget(), as we have changed the disk setup */
-	bforget(bh);
+static void bsd_partition(struct gendisk *hd, struct block_device *bdev,
+	int minor, int *current_minor)
+{
+#ifdef CONFIG_BSD_DISKLABEL
+	do_bsd_partition(hd, bdev, minor, current_minor, "bsd",
+		BSD_MAXPARTITIONS);
+#endif
+}
 
-	printk(" >\n");
+static void netbsd_partition(struct gendisk *hd, struct block_device *bdev,
+		int minor, int *current_minor)
+{
+#ifdef CONFIG_BSD_DISKLABEL
+	do_bsd_partition(hd, bdev, minor, current_minor, "netbsd",
+			BSD_MAXPARTITIONS);
+#endif
 }
+
+static void openbsd_partition(struct gendisk *hd, struct block_device *bdev,
+		int minor, int *current_minor)
+{
+#ifdef CONFIG_BSD_DISKLABEL
+	do_bsd_partition(hd, bdev, minor, current_minor,
+			"openbsd", OPENBSD_MAXPARTITIONS);
 #endif
+}
 
-#ifdef CONFIG_UNIXWARE_DISKLABEL
 /*
  * Create devices for Unixware partitions listed in a disklabel, under a
  * dos-like partition. See extended_partition() for more information.
  */
-static void unixware_partition(struct gendisk *hd, int minor) {
-	struct buffer_head *bh;
+static void unixware_partition(struct gendisk *hd, struct block_device *bdev,
+		int minor, int *current_minor)
+{
+#ifdef CONFIG_UNIXWARE_DISKLABEL
+	long offset = hd->part[minor].start_sect;
+	Sector sect;
 	struct unixware_disklabel *l;
 	struct unixware_slice *p;
 	int mask = (1 << hd->minor_shift) - 1;
 	char buf[40];
 
-	if (!(bh = get_partition_table_block(hd, minor, 14)))
+	l = (struct unixware_disklabel *)read_dev_sector(bdev, offset+29, &sect);
+	if (!l)
 		return;
-	l = (struct unixware_disklabel *) (bh->b_data+512);
 	if (le32_to_cpu(l->d_magic) != UNIXWARE_DISKMAGIC ||
 	    le32_to_cpu(l->vtoc.v_magic) != UNIXWARE_DISKMAGIC2) {
-		brelse(bh);
+		put_dev_sector(sect);
 		return;
 	}
 	printk(" %s: <unixware:", partition_name(hd, minor, buf));
 	p = &l->vtoc.v_slice[1];
 	/* I omit the 0th slice as it is the same as whole disk. */
 	while (p - &l->vtoc.v_slice[0] < UNIXWARE_NUMSLICE) {
-		if ((current_minor & mask) == 0)
+		if ((*current_minor & mask) == 0)
 			break;
 
 		if (p->s_label != UNIXWARE_FS_UNUSED) {
-			add_gd_partition(hd, current_minor, START_SECT(p),
+			add_gd_partition(hd, *current_minor, START_SECT(p),
 					 NR_SECTS(p));
-			current_minor++;
+			(*current_minor)++;
 		}
 		p++;
 	}
-	/* Use bforget, as we have changed the disk setup */
-	bforget(bh);
+	put_dev_sector(sect);
 	printk(" >\n");
-}
 #endif
+}
 
-#ifdef CONFIG_MINIX_SUBPARTITION
 /*
  * Minix 2.0.0/2.0.2 subpartition support.
  * Anand Krishnamurthy <anandk@wiproge.med.ge.com>
  * Rajeev V. Pillai    <rajeevvp@yahoo.com>
  */
-static void minix_partition(struct gendisk *hd, int minor)
+static void minix_partition(struct gendisk *hd, struct block_device *bdev,
+		int minor, int *current_minor)
 {
-	struct buffer_head *bh;
+#ifdef CONFIG_MINIX_SUBPARTITION
+	long offset = hd->part[minor].start_sect;
+	Sector sect;
+	unsigned char *data;
 	struct partition *p;
 	int mask = (1 << hd->minor_shift) - 1;
 	int i;
 	char buf[40];
 
-	if (!(bh = get_partition_table_block(hd, minor, 0)))
+	data = read_dev_sector(bdev, offset, &sect);
+	if (!data)
 		return;
-	bh->b_state = 0;
 
-	p = (struct partition *)(bh->b_data + 0x1be);
+	p = (struct partition *)(data + 0x1be);
 
 	/* The first sector of a Minix partition can have either
 	 * a secondary MBR describing its subpartitions, or
 	 * the normal boot sector. */
-	if (msdos_magic_present (bh->b_data + 510) &&
+	if (msdos_magic_present (data + 510) &&
 	    SYS_IND(p) == MINIX_PARTITION) { /* subpartition table present */
 
 		printk(" %s: <minix:", partition_name(hd, minor, buf));
 		for (i = 0; i < MINIX_NR_SUBPARTITIONS; i++, p++) {
-			if ((current_minor & mask) == 0)
+			if ((*current_minor & mask) == 0)
 				break;
 			/* add each partition in use */
 			if (SYS_IND(p) == MINIX_PARTITION) {
-				add_gd_partition(hd, current_minor,
+				add_gd_partition(hd, *current_minor,
 					      START_SECT(p), NR_SECTS(p));
-				current_minor++;
+				(*current_minor)++;
 			}
 		}
 		printk(" >\n");
 	}
-	brelse(bh);
-}
+	put_dev_sector(sect);
 #endif /* CONFIG_MINIX_SUBPARTITION */
- 
-int msdos_partition(struct gendisk *hd, kdev_t dev,
-		    unsigned long first_sector, int first_part_minor) {
-	int i, minor = current_minor = first_part_minor;
-	struct buffer_head *bh;
-	struct partition *p;
-	unsigned char *data;
-	int mask = (1 << hd->minor_shift) - 1;
-	int sector_size = get_hardsect_size(dev) / 512;
-#ifdef CONFIG_BLK_DEV_IDE
-	int tested_for_xlate = 0;
+}
 
-read_mbr:
-#endif /* CONFIG_BLK_DEV_IDE */
-	if (!(bh = bread(dev,0,get_ptable_blocksize(dev)))) {
-		if (warn_no_part) printk(" unable to read partition table\n");
-		return -1;
-	}
-	data = bh->b_data;
+static struct {
+	unsigned char id;
+	void (*parse)(struct gendisk *, struct block_device *, int, int *);
+} subtypes[] = {
+	{BSD_PARTITION, bsd_partition},
+	{NETBSD_PARTITION, netbsd_partition},
+	{OPENBSD_PARTITION, openbsd_partition},
+	{MINIX_PARTITION, minix_partition},
+	{UNIXWARE_PARTITION, unixware_partition},
+	{SOLARIS_X86_PARTITION, solaris_x86_partition},
+	{0, NULL},
+};
+/*
+ * Look for various forms of IDE disk geometry translation
+ */
+static int handle_ide_mess(struct block_device *bdev)
+{
 #ifdef CONFIG_BLK_DEV_IDE
-check_table:
-#endif /* CONFIG_BLK_DEV_IDE */
-	/* Use bforget(), because we may have changed the disk geometry */
+	Sector sect;
+	unsigned char *data;
+	kdev_t dev = to_kdev_t(bdev->bd_dev);
+	unsigned int sig;
+	int heads = 0;
+	struct partition *p;
+	int i;
+	/*
+	 * The i386 partition handling programs very often
+	 * make partitions end on cylinder boundaries.
+	 * There is no need to do so, and Linux fdisk doesnt always
+	 * do this, and Windows NT on Alpha doesnt do this either,
+	 * but still, this helps to guess #heads.
+	 */
+	data = read_dev_sector(bdev, 0, &sect);
+	if (!data)
+		return -1;
 	if (!msdos_magic_present(data + 510)) {
-		bforget(bh);
+		put_dev_sector(sect);
 		return 0;
 	}
+	sig = le16_to_cpu(*(unsigned short *)(data + 2));
 	p = (struct partition *) (data + 0x1be);
+	for (i = 0; i < 4; i++) {
+		struct partition *q = &p[i];
+		if (NR_SECTS(q)) {
+			if ((q->sector & 63) == 1 &&
+			    (q->end_sector & 63) == 63)
+				heads = q->end_head + 1;
+			break;
+		}
+	}
+	if (SYS_IND(p) == EZD_PARTITION) {
+		/*
+		 * Accesses to sector 0 must go to sector 1 instead.
+		 */
+		if (ide_xlate_1024(dev, -1, heads, " [EZD]"))
+			goto reread;
+	} else if (SYS_IND(p) == DM6_PARTITION) {
 
-#ifdef CONFIG_BLK_DEV_IDE
-	if (!tested_for_xlate++) {	/* Do this only once per disk */
 		/*
-		 * Look for various forms of IDE disk geometry translation
+		 * Everything on the disk is offset by 63 sectors,
+		 * including a "new" MBR with its own partition table.
 		 */
-		unsigned int sig = le16_to_cpu(*(unsigned short *)(data + 2));
-		int heads = 0;
+		if (ide_xlate_1024(dev, 1, heads, " [DM6:DDO]"))
+			goto reread;
+	} else if (sig <= 0x1ae &&
+		   data[sig] == 0xAA && data[sig+1] == 0x55 &&
+		   (data[sig+2] & 1)) {
+		/* DM6 signature in MBR, courtesy of OnTrack */
+		(void) ide_xlate_1024 (dev, 0, heads, " [DM6:MBR]");
+	} else if (SYS_IND(p) == DM6_AUX1PARTITION ||
+		   SYS_IND(p) == DM6_AUX3PARTITION) {
 		/*
-		 * The i386 partition handling programs very often
-		 * make partitions end on cylinder boundaries.
-		 * There is no need to do so, and Linux fdisk doesnt always
-		 * do this, and Windows NT on Alpha doesnt do this either,
-		 * but still, this helps to guess #heads.
+		 * DM6 on other than the first (boot) drive
 		 */
-		for (i = 0; i < 4; i++) {
-			struct partition *q = &p[i];
-			if (NR_SECTS(q)) {
-				if ((q->sector & 63) == 1 &&
-				    (q->end_sector & 63) == 63)
-					heads = q->end_head + 1;
-				break;
-			}
-		}
-		if (SYS_IND(p) == EZD_PARTITION) {
-			/*
-			 * Accesses to sector 0 must go to sector 1 instead.
-			 */
-			if (ide_xlate_1024(dev, -1, heads, " [EZD]")) {
-				data += 512;
-				goto check_table;
-			}
-		} else if (SYS_IND(p) == DM6_PARTITION) {
-
-			/*
-			 * Everything on the disk is offset by 63 sectors,
-			 * including a "new" MBR with its own partition table.
-			 */
-			if (ide_xlate_1024(dev, 1, heads, " [DM6:DDO]")) {
-				bforget(bh);
-				goto read_mbr;	/* start over with new MBR */
-			}
-		} else if (sig <= 0x1ae &&
-			   data[sig] == 0xAA && data[sig+1] == 0x55 &&
-			   (data[sig+2] & 1)) {
-			/* DM6 signature in MBR, courtesy of OnTrack */
-			(void) ide_xlate_1024 (dev, 0, heads, " [DM6:MBR]");
-		} else if (SYS_IND(p) == DM6_AUX1PARTITION ||
-			   SYS_IND(p) == DM6_AUX3PARTITION) {
-			/*
-			 * DM6 on other than the first (boot) drive
-			 */
-			(void) ide_xlate_1024(dev, 0, heads, " [DM6:AUX]");
-		} else {
-			(void) ide_xlate_1024(dev, 2, heads, " [PTBL]");
-		}
-	}
+		(void) ide_xlate_1024(dev, 0, heads, " [DM6:AUX]");
+	} else {
+		(void) ide_xlate_1024(dev, 2, heads, " [PTBL]");
+	}
+	put_dev_sector(sect);
+	return 1;
+
+reread:
+	put_dev_sector(sect);
+	/* Flush the cache */
+	invalidate_bdev(bdev, 1);
+	truncate_inode_pages(bdev->bd_inode->i_mapping, 0);
 #endif /* CONFIG_BLK_DEV_IDE */
+	return 1;
+}
+ 
+int msdos_partition(struct gendisk *hd, struct block_device *bdev,
+		    unsigned long first_sector, int first_part_minor)
+{
+	int i, minor = first_part_minor;
+	Sector sect;
+	struct partition *p;
+	unsigned char *data;
+	int mask = (1 << hd->minor_shift) - 1;
+	int sector_size = get_hardsect_size(to_kdev_t(bdev->bd_dev)) / 512;
+	int current_minor = first_part_minor;
+	int err;
+
+	err = handle_ide_mess(bdev);
+	if (err <= 0)
+		return err;
+	data = read_dev_sector(bdev, 0, &sect);
+	if (!data)
+		return -1;
+	if (!msdos_magic_present(data + 510)) {
+		put_dev_sector(sect);
+		return 0;
+	}
+	p = (struct partition *) (data + 0x1be);
 
-	/* Look for partitions in two passes:
-	   First find the primary partitions, and the DOS-type extended partitions.
-	   On the second pass look inside *BSD and Unixware and Solaris partitions. */
+	/*
+	 * Look for partitions in two passes:
+	 * First find the primary and DOS-type extended partitions.
+	 * On the second pass look inside *BSD, Unixware and Solaris partitions.
+	 */
 
-	current_minor += 4;  /* first "extra" minor (for extended partitions) */
+	current_minor += 4;
 	for (i=1 ; i<=4 ; minor++,i++,p++) {
 		if (!NR_SECTS(p))
 			continue;
-		add_gd_partition(hd, minor, first_sector+START_SECT(p)*sector_size,
-				 NR_SECTS(p)*sector_size);
+		add_gd_partition(hd, minor,
+				first_sector+START_SECT(p)*sector_size,
+				NR_SECTS(p)*sector_size);
 #if CONFIG_BLK_DEV_MD
 		if (SYS_IND(p) == LINUX_RAID_PARTITION) {
 			md_autodetect_dev(MKDEV(hd->major,minor));
@@ -530,20 +587,12 @@
 #endif
 		if (is_extended_partition(p)) {
 			printk(" <");
-			/*
-			 * If we are rereading the partition table, we need
-			 * to set the size of the partition so that we will
-			 * be able to bread the block containing the extended
-			 * partition info.
-			 */
-			hd->sizes[minor] = hd->part[minor].nr_sects 
-			  	>> (BLOCK_SIZE_BITS - 9);
-			extended_partition(hd, MKDEV(hd->major, minor));
-			printk(" >");
 			/* prevent someone doing mkfs or mkswap on an
 			   extended partition, but leave room for LILO */
 			if (hd->part[minor].nr_sects > 2)
 				hd->part[minor].nr_sects = 2;
+			extended_partition(hd, bdev, minor, &current_minor);
+			printk(" >");
 		}
 	}
 
@@ -567,29 +616,18 @@
 	minor -= 4;
 	p = (struct partition *) (0x1be + data);
 	for (i=1 ; i<=4 ; minor++,i++,p++) {
+		unsigned char id = SYS_IND(p);
+		int n;
+
 		if (!NR_SECTS(p))
 			continue;
-#ifdef CONFIG_BSD_DISKLABEL
-		if (SYS_IND(p) == BSD_PARTITION ||
-		    SYS_IND(p) == NETBSD_PARTITION ||
-		    SYS_IND(p) == OPENBSD_PARTITION)
-			bsd_disklabel_partition(hd, minor, SYS_IND(p));
-#endif
-#ifdef CONFIG_MINIX_SUBPARTITION
-		if (SYS_IND(p) == MINIX_PARTITION) {
-			minix_partition(hd, minor);
-		}
-#endif
-#ifdef CONFIG_UNIXWARE_DISKLABEL
-		if (SYS_IND(p) == UNIXWARE_PARTITION)
-			unixware_partition(hd, minor);
-#endif
-#ifdef CONFIG_SOLARIS_X86_PARTITION
-		if(SYS_IND(p) == SOLARIS_X86_PARTITION)
-			solaris_x86_partition(hd, minor);
-#endif
-	}
 
-	bforget(bh);
+		for (n = 0; subtypes[n].parse && id != subtypes[n].id; n++)
+			;
+
+		if (subtypes[n].parse)
+			subtypes[n].parse(hd, bdev, minor, &current_minor);
+	}
+	put_dev_sector(sect);
 	return 1;
 }
diff -urN linux-2.4.11-pre2/fs/partitions/msdos.h linux/fs/partitions/msdos.h
--- linux-2.4.11-pre2/fs/partitions/msdos.h	Thu Aug 12 12:26:06 1999
+++ linux/fs/partitions/msdos.h	Mon Dec  3 23:15:40 2001
@@ -4,6 +4,6 @@
 
 #define MSDOS_LABEL_MAGIC		0xAA55
 
-int msdos_partition(struct gendisk *hd, kdev_t dev,
+int msdos_partition(struct gendisk *hd, struct block_device *bdev,
 		    unsigned long first_sector, int first_part_minor);
 
diff -urN linux-2.4.11-pre2/fs/partitions/osf.c linux/fs/partitions/osf.c
--- linux-2.4.11-pre2/fs/partitions/osf.c	Fri Feb 16 16:02:37 2001
+++ linux/fs/partitions/osf.c	Mon Dec  3 23:15:40 2001
@@ -17,12 +17,13 @@
 #include "check.h"
 #include "osf.h"
 
-int osf_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector,
-		  int current_minor)
+int osf_partition(struct gendisk *hd, struct block_device *bdev,
+		unsigned long first_sector, int current_minor)
 {
 	int i;
+	Sector sect;
+	unsigned char *data;
 	int mask = (1 << hd->minor_shift) - 1;
-	struct buffer_head *bh;
 	struct disklabel {
 		u32 d_magic;
 		u16 d_type,d_subtype;
@@ -56,18 +57,18 @@
 	} * label;
 	struct d_partition * partition;
 
-	if (!(bh = bread(dev,0,get_ptable_blocksize(dev)))) {
-		if (warn_no_part) printk("unable to read partition table\n");
+	data = read_dev_sector(bdev, 0, &sect);
+	if (!data)
 		return -1;
-	}
-	label = (struct disklabel *) (bh->b_data+64);
+
+	label = (struct disklabel *) (data+64);
 	partition = label->d_partitions;
 	if (le32_to_cpu(label->d_magic) != DISKLABELMAGIC) {
-		brelse(bh);
+		put_dev_sector(sect);
 		return 0;
 	}
 	if (le32_to_cpu(label->d_magic2) != DISKLABELMAGIC) {
-		brelse(bh);
+		put_dev_sector(sect);
 		return 0;
 	}
 	for (i = 0 ; i < le16_to_cpu(label->d_npartitions); i++, partition++) {
@@ -80,7 +81,7 @@
 		current_minor++;
 	}
 	printk("\n");
-	brelse(bh);
+	put_dev_sector(sect);
 	return 1;
 }
 
diff -urN linux-2.4.11-pre2/fs/partitions/osf.h linux/fs/partitions/osf.h
--- linux-2.4.11-pre2/fs/partitions/osf.h	Thu Aug 12 12:26:06 1999
+++ linux/fs/partitions/osf.h	Mon Dec  3 23:15:40 2001
@@ -4,6 +4,6 @@
 
 #define DISKLABELMAGIC (0x82564557UL)
 
-int osf_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector,
-		  int current_minor);
+int osf_partition(struct gendisk *hd, struct block_device *bdev,
+		unsigned long first_sector, int current_minor);
 
diff -urN linux-2.4.11-pre2/fs/partitions/sgi.c linux/fs/partitions/sgi.c
--- linux-2.4.11-pre2/fs/partitions/sgi.c	Sun Mar 12 19:39:39 2000
+++ linux/fs/partitions/sgi.c	Mon Dec  3 23:15:40 2001
@@ -17,11 +17,12 @@
 #include "check.h"
 #include "sgi.h"
 
-int sgi_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, int current_minor)
+int sgi_partition(struct gendisk *hd, struct block_device *bdev, unsigned long first_sector, int current_minor)
 {
 	int i, csum, magic;
 	unsigned int *ui, start, blocks, cs;
-	struct buffer_head *bh;
+	Sector sect;
+	kdev_t dev = to_kdev_t(bdev->bd_dev);
 	struct sgi_disklabel {
 		int magic_mushroom;         /* Big fat spliff... */
 		short root_part_num;        /* Root partition number */
@@ -43,17 +44,15 @@
 	} *label;
 	struct sgi_partition *p;
 
-	if(!(bh = bread(dev, 0, get_ptable_blocksize(dev)))) {
-		if (warn_no_part) printk(KERN_WARNING "Dev %s: unable to read partition table\n", kdevname(dev));
+	label = (struct sgi_disklabel *) read_dev_sector(bdev, 0, &sect);
+	if (!label)
 		return -1;
-	}
-	label = (struct sgi_disklabel *) bh->b_data;
 	p = &label->partitions[0];
 	magic = label->magic_mushroom;
 	if(be32_to_cpu(magic) != SGI_LABEL_MAGIC) {
 		/*printk("Dev %s SGI disklabel: bad magic %08x\n",
-		       kdevname(dev), magic);*/
-		brelse(bh);
+		       bdevname(dev), magic);*/
+		put_dev_sector(sect);
 		return 0;
 	}
 	ui = ((unsigned int *) (label + 1)) - 1;
@@ -63,8 +62,8 @@
 	}
 	if(csum) {
 		printk(KERN_WARNING "Dev %s SGI disklabel: csum bad, label corrupted\n",
-		       kdevname(dev));
-		brelse(bh);
+		       bdevname(dev));
+		put_dev_sector(sect);
 		return 0;
 	}
 	/* All SGI disk labels have 16 partitions, disks under Linux only
@@ -81,6 +80,6 @@
 		current_minor++;
 	}
 	printk("\n");
-	brelse(bh);
+	put_dev_sector(sect);
 	return 1;
 }
diff -urN linux-2.4.11-pre2/fs/partitions/sgi.h linux/fs/partitions/sgi.h
--- linux-2.4.11-pre2/fs/partitions/sgi.h	Thu Aug 12 12:26:06 1999
+++ linux/fs/partitions/sgi.h	Mon Dec  3 23:15:40 2001
@@ -2,7 +2,7 @@
  *  fs/partitions/sgi.h
  */
 
-extern int sgi_partition(struct gendisk *hd, kdev_t dev,
+extern int sgi_partition(struct gendisk *hd, struct block_device *bdev,
 	 unsigned long first_sector, int first_part_minor);
 
 #define SGI_LABEL_MAGIC 0x0be5a941
diff -urN linux-2.4.11-pre2/fs/partitions/sun.c linux/fs/partitions/sun.c
--- linux-2.4.11-pre2/fs/partitions/sun.c	Wed Feb 16 15:42:06 2000
+++ linux/fs/partitions/sun.c	Mon Dec  3 23:15:40 2001
@@ -19,11 +19,12 @@
 #include "check.h"
 #include "sun.h"
 
-int sun_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, int first_part_minor)
+int sun_partition(struct gendisk *hd, struct block_device *bdev, unsigned long first_sector, int first_part_minor)
 {
 	int i, csum;
 	unsigned short *ush;
-	struct buffer_head *bh;
+	Sector sect;
+	kdev_t dev = to_kdev_t(bdev->bd_dev);
 	struct sun_disklabel {
 		unsigned char info[128];   /* Informative text string */
 		unsigned char spare[292];  /* Boot information etc. */
@@ -47,27 +48,25 @@
 	struct sun_partition *p;
 	unsigned long spc;
 
-	if(!(bh = bread(dev, 0, get_ptable_blocksize(dev)))) {
-		if (warn_no_part) printk(KERN_WARNING "Dev %s: unable to read partition table\n",
-		       kdevname(dev));
+	label = (struct sun_disklabel *)read_dev_sector(bdev, 0, &sect);
+	if (!label)
 		return -1;
-	}
-	label = (struct sun_disklabel *) bh->b_data;
+
 	p = label->partitions;
 	if (be16_to_cpu(label->magic) != SUN_LABEL_MAGIC) {
 /*		printk(KERN_INFO "Dev %s Sun disklabel: bad magic %04x\n",
-		       kdevname(dev), be16_to_cpu(label->magic)); */
-		brelse(bh);
+		       bdevname(dev), be16_to_cpu(label->magic)); */
+		put_dev_sector(sect);
 		return 0;
 	}
 	/* Look at the checksum */
 	ush = ((unsigned short *) (label+1)) - 1;
-	for(csum = 0; ush >= ((unsigned short *) label);)
+	for (csum = 0; ush >= ((unsigned short *) label);)
 		csum ^= *ush--;
 	if(csum) {
 		printk("Dev %s Sun disklabel: Csum bad, label corrupted\n",
-		       kdevname(dev));
-		brelse(bh);
+		       bdevname(dev));
+		put_dev_sector(sect);
 		return 0;
 	}
 	/* All Sun disks have 8 partition entries */
@@ -83,7 +82,6 @@
 		first_part_minor++;
 	}
 	printk("\n");
-	brelse(bh);
+	put_dev_sector(sect);
 	return 1;
 }
-
diff -urN linux-2.4.11-pre2/fs/partitions/sun.h linux/fs/partitions/sun.h
--- linux-2.4.11-pre2/fs/partitions/sun.h	Thu Aug 12 12:26:06 1999
+++ linux/fs/partitions/sun.h	Mon Dec  3 23:15:40 2001
@@ -4,6 +4,6 @@
 
 #define SUN_LABEL_MAGIC          0xDABE
 
-int sun_partition(struct gendisk *hd, kdev_t dev,
+int sun_partition(struct gendisk *hd, struct block_device *bdev,
 		  unsigned long first_sector, int first_part_minor);
 
diff -urN linux-2.4.11-pre2/fs/partitions/ultrix.c linux/fs/partitions/ultrix.c
--- linux-2.4.11-pre2/fs/partitions/ultrix.c	Sun Jul  9 22:21:41 2000
+++ linux/fs/partitions/ultrix.c	Mon Dec  3 23:15:40 2001
@@ -14,11 +14,12 @@
 
 #include "check.h"
 
-int ultrix_partition(struct gendisk *hd, kdev_t dev,
+int ultrix_partition(struct gendisk *hd, struct block_device *bdev,
                             unsigned long first_sector, int first_part_minor)
 {
 	int i;
-	struct buffer_head *bh;
+	Sector sect;
+	unsigned char *data;
 	struct ultrix_disklabel {
 		s32	pt_magic;	/* magic no. indicating part. info exits */
 		s32	pt_valid;	/* set by driver if pt is current */
@@ -31,18 +32,11 @@
 #define PT_MAGIC	0x032957	/* Partition magic number */
 #define PT_VALID	1		/* Indicates if struct is valid */
 
-#define	SBLOCK	((unsigned long)((16384 - sizeof(struct ultrix_disklabel)) \
-                  /get_ptable_blocksize(dev)))
-
-	bh = bread (dev, SBLOCK, get_ptable_blocksize(dev));
-	if (!bh) {
-		if (warn_no_part) printk (" unable to read block 0x%lx\n", SBLOCK);
+	data = read_dev_sector(bdev, (16384 - sizeof(*label))/512, &sect);
+	if (!data)
 		return -1;
-	}
 	
-	label = (struct ultrix_disklabel *)(bh->b_data
-                                            + get_ptable_blocksize(dev)
-                                            - sizeof(struct ultrix_disklabel));
+	label = (struct ultrix_disklabel *)(data + 512 - sizeof(*label));
 
 	if (label->pt_magic == PT_MAGIC && label->pt_valid == PT_VALID) {
 		for (i=0; i<8; i++, first_part_minor++)
@@ -50,11 +44,11 @@
 				add_gd_partition(hd, first_part_minor, 
 					      label->pt_part[i].pi_blkoff,
 					      label->pt_part[i].pi_nblocks);
-		brelse(bh);
+		put_dev_sector(sect);
 		printk ("\n");
 		return 1;
 	} else {
-		brelse(bh);
+		put_dev_sector(sect);
 		return 0;
 	}
 }
diff -urN linux-2.4.11-pre2/fs/partitions/ultrix.h linux/fs/partitions/ultrix.h
--- linux-2.4.11-pre2/fs/partitions/ultrix.h	Sun Jul  9 22:21:41 2000
+++ linux/fs/partitions/ultrix.h	Mon Dec  3 23:15:40 2001
@@ -2,6 +2,6 @@
  *  fs/partitions/ultrix.h
  */
 
-int ultrix_partition(struct gendisk *hd, kdev_t dev,
+int ultrix_partition(struct gendisk *hd, struct block_device *bdev,
                      unsigned long first_sector, int first_part_minor);
 
diff -urN linux-2.4.11-pre2/fs/smbfs/ChangeLog linux/fs/smbfs/ChangeLog
--- linux-2.4.11-pre2/fs/smbfs/ChangeLog	Wed Jun 20 16:07:57 2001
+++ linux/fs/smbfs/ChangeLog	Mon Dec  3 23:15:40 2001
@@ -1,5 +1,30 @@
 ChangeLog for smbfs.
 
+2001-09-17 Urban Widmark <urban@teststation.com>
+
+	* proc.c: Use 4096 (was 512) as the blocksize for better write
+	  performance (patch originally by Jan Kratochvil)
+	* proc.c: Skip disconnect smb, allows umount on unreachable servers.
+	* proc.c: Go back to the interruptible sleep as reconnects seem to
+	  handle it now.
+	* *.c: use autogenerated and private proto.h
+
+2000-11-22 Igor Zhbanov <bsg@uniyar.ac.ru>
+
+	* proc.c: fixed date_unix2dos for dates earlier than 01/01/1980
+	  and date_dos2unix for date==0 (from 2.2)
+
+2001-07-13 Rob Radez <rob@osinvestor.com>
+
+	* proc.c: make smb_errno return negative error values
+
+2001-07-09 Jochen Dolze <dolze@epcnet.de>
+
+	* inode.c: smb_statfs always returned success.
+	* proc.c, ioctl.c: Allow smbmount to signal failure to reconnect with
+	  a NULL argument to SMB_IOC_NEWCONN (speeds up error detection).
+	* proc.c: Add some of the missing error codes to smb_errno
+
 2001-06-12 Urban Widmark <urban@teststation.com>
 
 	* proc.c: replace the win95-flush fix with smb_seek, when needed.
diff -urN linux-2.4.11-pre2/fs/smbfs/Makefile linux/fs/smbfs/Makefile
--- linux-2.4.11-pre2/fs/smbfs/Makefile	Fri Feb 16 16:04:24 2001
+++ linux/fs/smbfs/Makefile	Mon Dec  3 23:15:40 2001
@@ -23,3 +23,19 @@
 #EXTRA_CFLAGS += -Werror
 
 include $(TOPDIR)/Rules.make
+
+#
+# Maintainer rules
+#
+
+# getopt.c not included. It is intentionally separate
+SRC = proc.c dir.c cache.c sock.c inode.c file.c ioctl.c
+
+proto:
+	-rm -f proto.h
+	@echo >  proto2.h "/*"
+	@echo >> proto2.h " *  Autogenerated with cproto on: " `date`
+	@echo >> proto2.h " */"
+	@echo >> proto2.h ""
+	cproto -E "gcc -E" -e -v -I $(TOPDIR)/include -DMAKING_PROTO -D__KERNEL__ $(SRC) >> proto2.h
+	mv proto2.h proto.h
diff -urN linux-2.4.11-pre2/fs/smbfs/cache.c linux/fs/smbfs/cache.c
--- linux-2.4.11-pre2/fs/smbfs/cache.c	Fri Mar 23 11:50:52 2001
+++ linux/fs/smbfs/cache.c	Mon Dec  3 23:15:40 2001
@@ -20,6 +20,7 @@
 #include <asm/page.h>
 
 #include "smb_debug.h"
+#include "proto.h"
 
 /*
  * Force the next attempt to use the cache to be a timeout.
diff -urN linux-2.4.11-pre2/fs/smbfs/dir.c linux/fs/smbfs/dir.c
--- linux-2.4.11-pre2/fs/smbfs/dir.c	Tue May 15 13:40:55 2001
+++ linux/fs/smbfs/dir.c	Mon Dec  3 23:15:40 2001
@@ -18,6 +18,7 @@
 #include <linux/smbno.h>
 
 #include "smb_debug.h"
+#include "proto.h"
 
 static int smb_readdir(struct file *, void *, filldir_t);
 static int smb_dir_open(struct inode *, struct file *);
@@ -452,8 +453,7 @@
 	if (!inode)
 		goto out_no_inode;
 
-	if (have_id)
-	{
+	if (have_id) {
 		inode->u.smbfs_i.fileid = fileid;
 		inode->u.smbfs_i.access = SMB_O_RDWR;
 		inode->u.smbfs_i.open = server->generation;
@@ -465,8 +465,7 @@
 out_no_inode:
 	error = -EACCES;
 out_close:
-	if (have_id)
-	{
+	if (have_id) {
 		PARANOIA("%s/%s failed, error=%d, closing %u\n",
 			 DENTRY_PATH(dentry), error, fileid);
 		smb_close_fileid(dentry, fileid);
@@ -562,12 +561,10 @@
 	 */
 	if (old_dentry->d_inode)
 		smb_close(old_dentry->d_inode);
-	if (new_dentry->d_inode)
-	{
+	if (new_dentry->d_inode) {
 		smb_close(new_dentry->d_inode);
 		error = smb_proc_unlink(new_dentry);
-		if (error)
-		{
+		if (error) {
 			VERBOSE("unlink %s/%s, error=%d\n",
 				DENTRY_PATH(new_dentry), error);
 			goto out;
@@ -579,8 +576,7 @@
 	smb_invalid_dir_cache(old_dir);
 	smb_invalid_dir_cache(new_dir);
 	error = smb_proc_mv(old_dentry, new_dentry);
-	if (!error)
-	{
+	if (!error) {
 		smb_renew_times(old_dentry);
 		smb_renew_times(new_dentry);
 	}
diff -urN linux-2.4.11-pre2/fs/smbfs/file.c linux/fs/smbfs/file.c
--- linux-2.4.11-pre2/fs/smbfs/file.c	Sun Aug 12 11:13:59 2001
+++ linux/fs/smbfs/file.c	Mon Dec  3 23:15:40 2001
@@ -24,6 +24,7 @@
 #include <linux/smb_fs.h>
 
 #include "smb_debug.h"
+#include "proto.h"
 
 static int
 smb_fsync(struct file *file, struct dentry * dentry, int datasync)
diff -urN linux-2.4.11-pre2/fs/smbfs/inode.c linux/fs/smbfs/inode.c
--- linux-2.4.11-pre2/fs/smbfs/inode.c	Mon Dec  3 23:15:30 2001
+++ linux/fs/smbfs/inode.c	Mon Dec  3 23:15:40 2001
@@ -32,6 +32,7 @@
 
 #include "smb_debug.h"
 #include "getopt.h"
+#include "proto.h"
 
 /* Always pick a default string */
 #ifdef CONFIG_SMB_NLS_REMOTE
@@ -259,7 +260,7 @@
 }
 
 /* FIXME: flags and has_arg could probably be merged. */
-struct option opts[] = {
+static struct option opts[] = {
 	{ "version",	1, 0, 'v' },
 	{ "win95",	0, SMB_MOUNT_WIN95, 1 },
 	{ "oldattr",	0, SMB_MOUNT_OLDATTR, 1 },
@@ -344,7 +345,6 @@
 	struct smb_sb_info *server = &(sb->u.smbfs_sb);
 
 	if (server->sock_file) {
-		smb_proc_disconnect(server);
 		smb_dont_catch_keepalive(server);
 		fput(server->sock_file);
 	}
@@ -353,23 +353,24 @@
 	       kill_proc(server->conn_pid, SIGTERM, 1);
 
 	smb_kfree(server->mnt);
-	smb_kfree(sb->u.smbfs_sb.temp_buf);
+	smb_kfree(server->temp_buf);
 	if (server->packet)
 		smb_vfree(server->packet);
 
-	if(sb->u.smbfs_sb.remote_nls) {
-		unload_nls(sb->u.smbfs_sb.remote_nls);
-		sb->u.smbfs_sb.remote_nls = NULL;
-	}
-	if(sb->u.smbfs_sb.local_nls) {
-		unload_nls(sb->u.smbfs_sb.local_nls);
-		sb->u.smbfs_sb.local_nls = NULL;
+	if (server->remote_nls) {
+		unload_nls(server->remote_nls);
+		server->remote_nls = NULL;
+	}
+	if (server->local_nls) {
+		unload_nls(server->local_nls);
+		server->local_nls = NULL;
 	}
 }
 
 struct super_block *
 smb_read_super(struct super_block *sb, void *raw_data, int silent)
 {
+	struct smb_sb_info *server = &sb->u.smbfs_sb;
 	struct smb_mount_data_kernel *mnt;
 	struct smb_mount_data *oldmnt;
 	struct inode *root_inode;
@@ -389,34 +390,34 @@
 	sb->s_magic = SMB_SUPER_MAGIC;
 	sb->s_op = &smb_sops;
 
-	sb->u.smbfs_sb.mnt = NULL;
-	sb->u.smbfs_sb.sock_file = NULL;
-	init_MUTEX(&sb->u.smbfs_sb.sem);
-	init_waitqueue_head(&sb->u.smbfs_sb.wait);
-	sb->u.smbfs_sb.conn_pid = 0;
-	sb->u.smbfs_sb.state = CONN_INVALID; /* no connection yet */
-	sb->u.smbfs_sb.generation = 0;
-	sb->u.smbfs_sb.packet_size = smb_round_length(SMB_INITIAL_PACKET_SIZE);
-	sb->u.smbfs_sb.packet = smb_vmalloc(sb->u.smbfs_sb.packet_size);
-	if (!sb->u.smbfs_sb.packet)
+	server->mnt = NULL;
+	server->sock_file = NULL;
+	init_MUTEX(&server->sem);
+	init_waitqueue_head(&server->wait);
+	server->conn_pid = 0;
+	server->state = CONN_INVALID; /* no connection yet */
+	server->generation = 0;
+	server->packet_size = smb_round_length(SMB_INITIAL_PACKET_SIZE);
+	server->packet = smb_vmalloc(server->packet_size);
+	if (!server->packet)
 		goto out_no_mem;
 
 	/* Allocate the global temp buffer */
-	sb->u.smbfs_sb.temp_buf = smb_kmalloc(2*SMB_MAXPATHLEN+20, GFP_KERNEL);
-	if (!sb->u.smbfs_sb.temp_buf)
+	server->temp_buf = smb_kmalloc(2*SMB_MAXPATHLEN+20, GFP_KERNEL);
+	if (!server->temp_buf)
 		goto out_no_temp;
 
 	/* Setup NLS stuff */
-	sb->u.smbfs_sb.remote_nls = NULL;
-	sb->u.smbfs_sb.local_nls = NULL;
-	sb->u.smbfs_sb.name_buf = sb->u.smbfs_sb.temp_buf + SMB_MAXPATHLEN + 20;
+	server->remote_nls = NULL;
+	server->local_nls = NULL;
+	server->name_buf = server->temp_buf + SMB_MAXPATHLEN + 20;
 
 	/* Allocate the mount data structure */
 	/* FIXME: merge this with the other malloc and get a whole page? */
 	mnt = smb_kmalloc(sizeof(struct smb_mount_data_kernel), GFP_KERNEL);
 	if (!mnt)
 		goto out_no_mount;
-	sb->u.smbfs_sb.mnt = mnt;
+	server->mnt = mnt;
 
 	memset(mnt, 0, sizeof(struct smb_mount_data_kernel));
 	strncpy(mnt->codepage.local_name, CONFIG_NLS_DEFAULT,
@@ -447,9 +448,7 @@
 
 		mnt->mounted_uid = current->uid;
 	}
-	smb_setcodepage(&sb->u.smbfs_sb, &mnt->codepage);
-	if (!sb->u.smbfs_sb.convert)
-		PARANOIA("convert funcptr was NULL!\n");
+	smb_setcodepage(server, &mnt->codepage);
 
 	/*
 	 * Display the enabled options
@@ -463,7 +462,7 @@
 	/*
 	 * Keep the super block locked while we get the root inode.
 	 */
-	smb_init_root_dirent(&(sb->u.smbfs_sb), &root);
+	smb_init_root_dirent(server, &root);
 	root_inode = smb_iget(sb, &root);
 	if (!root_inode)
 		goto out_no_root;
@@ -478,13 +477,13 @@
 out_no_root:
 	iput(root_inode);
 out_bad_option:
-	smb_kfree(sb->u.smbfs_sb.mnt);
+	smb_kfree(server->mnt);
 out_no_mount:
-	smb_kfree(sb->u.smbfs_sb.temp_buf);
+	smb_kfree(server->temp_buf);
 out_no_temp:
-	smb_vfree(sb->u.smbfs_sb.packet);
+	smb_vfree(server->packet);
 out_no_mem:
-	if (!sb->u.smbfs_sb.mnt)
+	if (!server->mnt)
 		printk(KERN_ERR "smb_read_super: allocation failure\n");
 	goto out_fail;
 out_wrong_data:
@@ -499,11 +498,11 @@
 static int
 smb_statfs(struct super_block *sb, struct statfs *buf)
 {
-	smb_proc_dskattr(sb, buf);
+	int result = smb_proc_dskattr(sb, buf);
 
 	buf->f_type = SMB_SUPER_MAGIC;
 	buf->f_namelen = SMB_MAXPATHLEN;
-	return 0;
+	return result;
 }
 
 int
@@ -532,8 +531,7 @@
 	if ((attr->ia_valid & ATTR_MODE) && (attr->ia_mode & ~mask))
 		goto out;
 
-	if ((attr->ia_valid & ATTR_SIZE) != 0)
-	{
+	if ((attr->ia_valid & ATTR_SIZE) != 0) {
 		VERBOSE("changing %s/%s, old size=%ld, new size=%ld\n",
 			DENTRY_PATH(dentry),
 			(long) inode->i_size, (long) attr->ia_size);
@@ -558,20 +556,17 @@
 	smb_get_inode_attr(inode, &fattr);
 
 	changed = 0;
-	if ((attr->ia_valid & ATTR_MTIME) != 0)
-	{
+	if ((attr->ia_valid & ATTR_MTIME) != 0) {
 		fattr.f_mtime = attr->ia_mtime;
 		changed = 1;
 	}
-	if ((attr->ia_valid & ATTR_ATIME) != 0)
-	{
+	if ((attr->ia_valid & ATTR_ATIME) != 0) {
 		fattr.f_atime = attr->ia_atime;
 		/* Earlier protocols don't have an access time */
 		if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2)
 			changed = 1;
 	}
-	if (changed)
-	{
+	if (changed) {
 		error = smb_proc_settime(dentry, &fattr);
 		if (error)
 			goto out;
@@ -582,27 +577,22 @@
 	 * Check for mode changes ... we're extremely limited in
 	 * what can be set for SMB servers: just the read-only bit.
 	 */
-	if ((attr->ia_valid & ATTR_MODE) != 0)
-	{
+	if ((attr->ia_valid & ATTR_MODE) != 0) {
 		VERBOSE("%s/%s mode change, old=%x, new=%x\n",
 			DENTRY_PATH(dentry), fattr.f_mode, attr->ia_mode);
 		changed = 0;
-		if (attr->ia_mode & S_IWUSR)
-		{
-			if (fattr.attr & aRONLY)
-			{
+		if (attr->ia_mode & S_IWUSR) {
+			if (fattr.attr & aRONLY) {
 				fattr.attr &= ~aRONLY;
 				changed = 1;
 			}
 		} else {
-			if (!(fattr.attr & aRONLY))
-			{
+			if (!(fattr.attr & aRONLY)) {
 				fattr.attr |= aRONLY;
 				changed = 1;
 			}
 		}
-		if (changed)
-		{
+		if (changed) {
 			error = smb_proc_setattr(dentry, &fattr);
 			if (error)
 				goto out;
diff -urN linux-2.4.11-pre2/fs/smbfs/ioctl.c linux/fs/smbfs/ioctl.c
--- linux-2.4.11-pre2/fs/smbfs/ioctl.c	Tue May 15 13:40:55 2001
+++ linux/fs/smbfs/ioctl.c	Mon Dec  3 23:15:40 2001
@@ -19,6 +19,8 @@
 
 #include <asm/uaccess.h>
 
+#include "proto.h"
+
 int
 smb_ioctl(struct inode *inode, struct file *filp,
 	  unsigned int cmd, unsigned long arg)
@@ -37,9 +39,11 @@
 		break;
 
 	case SMB_IOC_NEWCONN:
-		/* require an argument == smb_conn_opt, else it is EINVAL */
-		if (!arg)
+		/* arg is smb_conn_opt, or NULL if no connection was made */
+		if (!arg) {
+			result = smb_wakeup(server);
 			break;
+		}
 
 		result = -EFAULT;
 		if (!copy_from_user(&opt, (void *)arg, sizeof(opt)))
diff -urN linux-2.4.11-pre2/fs/smbfs/proc.c linux/fs/smbfs/proc.c
--- linux-2.4.11-pre2/fs/smbfs/proc.c	Wed Jun 20 16:07:57 2001
+++ linux/fs/smbfs/proc.c	Mon Dec  3 23:15:40 2001
@@ -23,16 +23,18 @@
 #include <linux/smb_mount.h>
 
 #include <asm/string.h>
+#include <asm/div64.h>
 
 #include "smb_debug.h"
+#include "proto.h"
 
 
 /* Features. Undefine if they cause problems, this should perhaps be a
    config option. */
 #define SMBFS_POSIX_UNLINK 1
 
-/* Allow smb_retry to be interrupted. Not sure of the benefit ... */
-/* #define SMB_RETRY_INTR */
+/* Allow smb_retry to be interrupted. */
+#define SMB_RETRY_INTR
 
 #define SMB_VWV(packet)  ((packet) + SMB_HEADER_LEN)
 #define SMB_CMD(packet)  (*(packet+8))
@@ -43,6 +45,9 @@
 #define SMB_DIRINFO_SIZE 43
 #define SMB_STATUS_SIZE  21
 
+#define SMB_ST_BLKSIZE	(PAGE_SIZE)
+#define SMB_ST_BLKSHIFT	(PAGE_SHIFT)
+
 static int
 smb_proc_setattr_ext(struct smb_sb_info *, struct inode *,
 		     struct smb_fattr *);
@@ -137,8 +142,7 @@
 	return len;
 }
 
-static int setcodepage(struct smb_sb_info *server,
-		       struct nls_table **p, char *name)
+static int setcodepage(struct nls_table **p, char *name)
 {
 	struct nls_table *nls;
 
@@ -160,16 +164,20 @@
 /* Handles all changes to codepage settings. */
 int smb_setcodepage(struct smb_sb_info *server, struct smb_nls_codepage *cp)
 {
-	int n;
+	int n = 0;
 
 	smb_lock_server(server);
 
-	n = setcodepage(server, &server->local_nls, cp->local_name);
+	/* Don't load any nls_* at all, if no remote is requested */
+	if (!*cp->remote_name)
+		goto out;
+
+	n = setcodepage(&server->local_nls, cp->local_name);
 	if (n != 0)
 		goto out;
-	n = setcodepage(server, &server->remote_nls, cp->remote_name);
+	n = setcodepage(&server->remote_nls, cp->remote_name);
 	if (n != 0)
-		setcodepage(server, &server->local_nls, NULL);
+		setcodepage(&server->local_nls, NULL);
 
 out:
 	if (server->local_nls != NULL && server->remote_nls != NULL)
@@ -188,7 +196,7 @@
 /*                                                                           */
 /*****************************************************************************/
 
-__u8 *
+static __u8 *
 smb_encode_smb_length(__u8 * p, __u32 len)
 {
 	*p = 0;
@@ -308,7 +316,9 @@
 	int month, year;
 	time_t secs;
 
-	month = ((date >> 5) & 15) - 1;
+	/* first subtract and mask after that... Otherwise, if
+	   date == 0, bad things happen */
+	month = ((date >> 5) - 1) & 15;
 	year = date >> 9;
 	secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 + 86400 *
 	    ((date & 31) - 1 + day_n[month] + (year / 4) + year * 365 - ((year & 3) == 0 &&
@@ -327,6 +337,9 @@
 	int day, year, nl_day, month;
 
 	unix_date = utc2local(server, unix_date);
+	if (unix_date < 315532800)
+		unix_date = 315532800;
+
 	*time = (unix_date % 60) / 2 +
 		(((unix_date / 60) % 60) << 5) +
 		(((unix_date / 3600) % 24) << 11);
@@ -350,57 +363,20 @@
 
 /* The following are taken from fs/ntfs/util.c */
 
+#define NTFS_TIME_OFFSET ((u64)(369*365 + 89) * 24 * 3600 * 10000000)
+
 /*
  * Convert the NT UTC (based 1601-01-01, in hundred nanosecond units)
  * into Unix UTC (based 1970-01-01, in seconds).
- *
- * This is very gross because
- * 1: We must do 64-bit division on a 32-bit machine
- * 2: We can't use libgcc for long long operations in the kernel
- * 3: Floating point math in the kernel would corrupt user data
  */
 static time_t
-smb_ntutc2unixutc(struct smb_sb_info *server, u64 ntutc)
+smb_ntutc2unixutc(u64 ntutc)
 {
-	const unsigned int D = 10000000;
-	unsigned int H = (unsigned int)(ntutc >> 32);
-	unsigned int L = (unsigned int)ntutc;
-	unsigned int numerator2;
-	unsigned int lowseconds;
-	unsigned int result;
-
-	/*
-	 * It is best to subtract 0x019db1ded53e8000 first.
-	 * Then the 1601-based date becomes a 1970-based date.
-	 */
-	if (L < (unsigned)0xd53e8000) H--;
-	L -= (unsigned)0xd53e8000;
-	H -= (unsigned)0x019db1de;
-
-	/*
-	 * Now divide 64-bit numbers on a 32-bit machine :-)
-	 * With the subtraction already done, the result fits in 32 bits.
-	 * The numerator fits in 56 bits and the denominator fits
-	 * in 24 bits, so we can shift by 8 bits to make this work.
-	 */
-
-	numerator2  = (H<<8) | (L>>24);
-	result      = (numerator2 / D);   /* shifted 24 right!! */
-	lowseconds  = result << 24;
-
-	numerator2  = ((numerator2-result*D)<<8) | ((L>>16)&0xff);
-	result      = (numerator2 / D);   /* shifted 16 right!! */
-	lowseconds |= result << 16;
-
-	numerator2  = ((numerator2-result*D)<<8) | ((L>>8)&0xff);
-	result      = (numerator2 / D);   /* shifted 8 right!! */
-	lowseconds |= result << 8;
-
-	numerator2  = ((numerator2-result*D)<<8) | (L&0xff);
-	result      = (numerator2 / D);   /* not shifted */
-	lowseconds |= result;
-
-	return lowseconds;
+	/* FIXME: what about the timezone difference? */
+	/* Subtract the NTFS time offset, then convert to 1s intervals. */
+	u64 t = ntutc - NTFS_TIME_OFFSET;
+	do_div(t, 10000000);
+	return (time_t)t;
 }
 
 #if 0
@@ -409,7 +385,7 @@
 smb_unixutc2ntutc(struct smb_sb_info *server, time_t t)
 {
 	/* Note: timezone conversion is probably wrong. */
-	return ((utc2local(server, t) + (u64)(369*365+89)*24*3600) * 10000000);
+	return ((u64)utc2local(server, t)) * 10000000 + NTFS_TIME_OFFSET;
 }
 #endif
 
@@ -519,6 +495,9 @@
 	return size;
 }
 
+/*
+ * Convert SMB error codes to -E... errno values.
+ */
 int
 smb_errno(struct smb_sb_info *server)
 {
@@ -529,110 +508,115 @@
 	VERBOSE("errcls %d  code %d  from command 0x%x\n",
 		errcls, error, SMB_CMD(server->packet));
 
-	if (errcls == ERRDOS)
-		switch (error)
-		{
+	if (errcls == ERRDOS) {
+		switch (error) {
 		case ERRbadfunc:
-			return EINVAL;
+			return -EINVAL;
 		case ERRbadfile:
 		case ERRbadpath:
-			return ENOENT;
+			return -ENOENT;
 		case ERRnofids:
-			return EMFILE;
+			return -EMFILE;
 		case ERRnoaccess:
-			return EACCES;
+			return -EACCES;
 		case ERRbadfid:
-			return EBADF;
+			return -EBADF;
 		case ERRbadmcb:
-			return EREMOTEIO;
+			return -EREMOTEIO;
 		case ERRnomem:
-			return ENOMEM;
+			return -ENOMEM;
 		case ERRbadmem:
-			return EFAULT;
+			return -EFAULT;
 		case ERRbadenv:
 		case ERRbadformat:
-			return EREMOTEIO;
+			return -EREMOTEIO;
 		case ERRbadaccess:
-			return EACCES;
+			return -EACCES;
 		case ERRbaddata:
-			return E2BIG;
+			return -E2BIG;
 		case ERRbaddrive:
-			return ENXIO;
+			return -ENXIO;
 		case ERRremcd:
-			return EREMOTEIO;
+			return -EREMOTEIO;
 		case ERRdiffdevice:
-			return EXDEV;
-		case ERRnofiles:	/* Why is this mapped to 0?? */
-			return 0;
+			return -EXDEV;
+		case ERRnofiles:
+			return -ENOENT;
 		case ERRbadshare:
-			return ETXTBSY;
+			return -ETXTBSY;
 		case ERRlock:
-			return EDEADLK;
+			return -EDEADLK;
 		case ERRfilexists:
-			return EEXIST;
-		case 87:		/* should this map to 0?? */
-			return 0;	/* Unknown error!! */
-		case 123:		/* Invalid name?? e.g. .tmp* */
-			return ENOENT;
-		case 145:		/* Win NT 4.0: non-empty directory? */
-			return ENOTEMPTY;
-			/* This next error seems to occur on an mv when
-			 * the destination exists */
-		case 183:
-			return EEXIST;
+			return -EEXIST;
+		case ERRinvalidparam:
+			return -EINVAL;
+		case ERRdiskfull:
+			return -ENOSPC;
+		case ERRinvalidname:
+			return -ENOENT;
+		case ERRdirnotempty:
+			return -ENOTEMPTY;
+		case ERRnotlocked:
+                       return -ENOLCK;
+		case ERRexists:
+			return -EEXIST;
 		default:
 			class = "ERRDOS";
 			goto err_unknown;
-	} else if (errcls == ERRSRV)
-		switch (error)
-		{
+		}
+	} else if (errcls == ERRSRV) {
+		switch (error) {
 		/* N.B. This is wrong ... EIO ? */
 		case ERRerror:
-			return ENFILE;
+			return -ENFILE;
 		case ERRbadpw:
-			return EINVAL;
+			return -EINVAL;
 		case ERRbadtype:
-			return EIO;
+			return -EIO;
 		case ERRaccess:
-			return EACCES;
+			return -EACCES;
 		/*
 		 * This is a fatal error, as it means the "tree ID"
 		 * for this connection is no longer valid. We map
 		 * to a special error code and get a new connection.
 		 */
 		case ERRinvnid:
-			return EBADSLT;
+			return -EBADSLT;
 		default:
 			class = "ERRSRV";
 			goto err_unknown;
-	} else if (errcls == ERRHRD)
-		switch (error)
-		{
+		}
+	} else if (errcls == ERRHRD) {
+		switch (error) {
 		case ERRnowrite:
-			return EROFS;
+			return -EROFS;
 		case ERRbadunit:
-			return ENODEV;
+			return -ENODEV;
 		case ERRnotready:
-			return EUCLEAN;
+			return -EUCLEAN;
 		case ERRbadcmd:
 		case ERRdata:
-			return EIO;
+			return -EIO;
 		case ERRbadreq:
-			return ERANGE;
+			return -ERANGE;
 		case ERRbadshare:
-			return ETXTBSY;
+			return -ETXTBSY;
 		case ERRlock:
-			return EDEADLK;
+			return -EDEADLK;
 		default:
 			class = "ERRHRD";
 			goto err_unknown;
-	} else if (errcls == ERRCMD)
+		}
+	} else if (errcls == ERRCMD) {
 		class = "ERRCMD";
+	} else if (errcls == SUCCESS) {
+		return 0;	/* This is the only valid 0 return */
+	}
 
 err_unknown:
 	printk(KERN_ERR "smb_errno: class %s, code %d from command 0x%x\n",
 	       class, error, SMB_CMD(server->packet));
-	return EIO;
+	return -EIO;
 }
 
 /*
@@ -749,12 +733,10 @@
 	}
 
 	/*
-	 * Check for server errors.  The current smb_errno() routine
-	 * is squashing some error codes, but I don't think this is
-	 * correct: after a server error the packet won't be valid.
+	 * Check for server errors.
 	 */
 	if (s->rcls != 0) {
-		result = -smb_errno(s);
+		result = smb_errno(s);
 		if (!result)
 			printk(KERN_DEBUG "smb_request_ok: rcls=%d, err=%d mapped to 0\n",
 				s->rcls, s->err);
@@ -850,17 +832,23 @@
 
 out:
 	smb_unlock_server(server);
+	smb_wakeup(server);
+	return error;
+
+out_putf:
+	fput(filp);
+	goto out;
+}
 
+int
+smb_wakeup(struct smb_sb_info *server)
+{
 #ifdef SMB_RETRY_INTR
 	wake_up_interruptible(&server->wait);
 #else
 	wake_up(&server->wait);
 #endif
-	return error;
-
-out_putf:
-	fput(filp);
-	goto out;
+	return 0;
 }
 
 /* smb_setup_header: We completely set up the packet. You only have to
@@ -1490,7 +1478,7 @@
 	fattr->f_nlink = 1;
 	fattr->f_uid = server->mnt->uid;
 	fattr->f_gid = server->mnt->gid;
-	fattr->f_blksize = 512;
+	fattr->f_blksize = SMB_ST_BLKSIZE;
 }
 
 static void
@@ -1500,18 +1488,16 @@
 	if (fattr->attr & aDIR)
 	{
 		fattr->f_mode = server->mnt->dir_mode;
-		fattr->f_size = 512;
+		fattr->f_size = SMB_ST_BLKSIZE;
 	}
 	/* Check the read-only flag */
 	if (fattr->attr & aRONLY)
 		fattr->f_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
 
+	/* How many 512 byte blocks do we need for this file? */
 	fattr->f_blocks = 0;
-	if ((fattr->f_blksize != 0) && (fattr->f_size != 0))
-	{
-		fattr->f_blocks =
-		    (fattr->f_size - 1) / fattr->f_blksize + 1;
-	}
+	if (fattr->f_size != 0)
+		fattr->f_blocks = 1 + ((fattr->f_size-1) >> 9);
 	return;
 }
 
@@ -1770,9 +1756,9 @@
 		if (len && qname->name[len-1] == '\0')
 			len--;
 
-		fattr->f_ctime = smb_ntutc2unixutc(server, LVAL(p, 8));
-		fattr->f_atime = smb_ntutc2unixutc(server, LVAL(p, 16));
-		fattr->f_mtime = smb_ntutc2unixutc(server, LVAL(p, 24));
+		fattr->f_ctime = smb_ntutc2unixutc(LVAL(p, 8));
+		fattr->f_atime = smb_ntutc2unixutc(LVAL(p, 16));
+		fattr->f_mtime = smb_ntutc2unixutc(LVAL(p, 24));
 		/* change time (32) */
 		fattr->f_size = DVAL(p, 40);
 		/* alloc size (48) */
@@ -1940,7 +1926,7 @@
                 }
 
 		if (server->rcls != 0) {
-			result = -smb_errno(server);
+			result = smb_errno(server);
 			PARANOIA("name=%s, result=%d, rcls=%d, err=%d\n",
 				 mask, result, server->rcls, server->err);
 			break;
@@ -2104,7 +2090,7 @@
 	}
 	if (server->rcls != 0)
 	{ 
-		result = -smb_errno(server);
+		result = smb_errno(server);
 #ifdef SMBFS_PARANOIA
 		if (result != -ENOENT)
 			PARANOIA("error for %s, rcls=%d, err=%d\n",
@@ -2227,7 +2213,7 @@
 	{
 		VERBOSE("for %s: result=%d, rcls=%d, err=%d\n",
 			&param[6], result, server->rcls, server->err);
-		result = -smb_errno(server);
+		result = smb_errno(server);
 		goto out;
 	}
 	result = -ENOENT;
@@ -2490,7 +2476,7 @@
 	}
 	result = 0;
 	if (server->rcls != 0)
-		result = -smb_errno(server);
+		result = smb_errno(server);
 
 out:
 	return result;
@@ -2559,6 +2545,7 @@
 	struct smb_sb_info *server = &(sb->u.smbfs_sb);
 	int result;
 	char *p;
+	long unit;
 
 	smb_lock_server(server);
 
@@ -2571,23 +2558,13 @@
 		goto out;
 	}
 	p = SMB_VWV(server->packet);
-	attr->f_blocks = WVAL(p, 0);
-	attr->f_bsize  = WVAL(p, 2) * WVAL(p, 4);
-	attr->f_bavail = attr->f_bfree = WVAL(p, 6);
+	unit = (WVAL(p, 2) * WVAL(p, 4)) >> SMB_ST_BLKSHIFT;
+	attr->f_blocks = WVAL(p, 0) * unit;
+	attr->f_bsize  = SMB_ST_BLKSIZE;
+	attr->f_bavail = attr->f_bfree = WVAL(p, 6) * unit;
 	result = 0;
 
 out:
-	smb_unlock_server(server);
-	return result;
-}
-
-int
-smb_proc_disconnect(struct smb_sb_info *server)
-{
-	int result;
-	smb_lock_server(server);
-	smb_setup_header(server, SMBtdis, 0, 0);
-	result = smb_request_ok(server, SMBtdis, 0, 0);
 	smb_unlock_server(server);
 	return result;
 }
diff -urN linux-2.4.11-pre2/fs/smbfs/proto.h linux/fs/smbfs/proto.h
--- linux-2.4.11-pre2/fs/smbfs/proto.h	Wed Dec 31 16:00:00 1969
+++ linux/fs/smbfs/proto.h	Mon Dec  3 23:15:40 2001
@@ -0,0 +1,63 @@
+/*
+ *  Autogenerated with cproto on:  Tue Oct 2 20:40:54 CEST 2001
+ */
+
+/* proc.c */
+extern int smb_setcodepage(struct smb_sb_info *server, struct smb_nls_codepage *cp);
+extern __u32 smb_len(__u8 *p);
+extern int smb_get_rsize(struct smb_sb_info *server);
+extern int smb_get_wsize(struct smb_sb_info *server);
+extern int smb_errno(struct smb_sb_info *server);
+extern int smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt);
+extern int smb_wakeup(struct smb_sb_info *server);
+extern __u8 *smb_setup_header(struct smb_sb_info *server, __u8 command, __u16 wct, __u16 bcc);
+extern int smb_open(struct dentry *dentry, int wish);
+extern int smb_close(struct inode *ino);
+extern int smb_close_fileid(struct dentry *dentry, __u16 fileid);
+extern int smb_proc_read(struct inode *inode, off_t offset, int count, char *data);
+extern int smb_proc_write(struct inode *inode, off_t offset, int count, const char *data);
+extern int smb_proc_create(struct dentry *dentry, __u16 attr, time_t ctime, __u16 *fileid);
+extern int smb_proc_mv(struct dentry *old_dentry, struct dentry *new_dentry);
+extern int smb_proc_mkdir(struct dentry *dentry);
+extern int smb_proc_rmdir(struct dentry *dentry);
+extern int smb_proc_unlink(struct dentry *dentry);
+extern int smb_proc_flush(struct smb_sb_info *server, __u16 fileid);
+extern int smb_proc_trunc(struct smb_sb_info *server, __u16 fid, __u32 length);
+extern void smb_init_root_dirent(struct smb_sb_info *server, struct smb_fattr *fattr);
+extern int smb_proc_readdir(struct file *filp, void *dirent, filldir_t filldir, struct smb_cache_control *ctl);
+extern int smb_proc_getattr(struct dentry *dir, struct smb_fattr *fattr);
+extern int smb_proc_setattr(struct dentry *dir, struct smb_fattr *fattr);
+extern int smb_proc_settime(struct dentry *dentry, struct smb_fattr *fattr);
+extern int smb_proc_dskattr(struct super_block *sb, struct statfs *attr);
+/* dir.c */
+extern struct file_operations smb_dir_operations;
+extern struct inode_operations smb_dir_inode_operations;
+extern void smb_new_dentry(struct dentry *dentry);
+extern void smb_renew_times(struct dentry *dentry);
+/* cache.c */
+extern void smb_invalid_dir_cache(struct inode *dir);
+extern void smb_invalidate_dircache_entries(struct dentry *parent);
+extern struct dentry *smb_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos);
+extern int smb_fill_cache(struct file *filp, void *dirent, filldir_t filldir, struct smb_cache_control *ctrl, struct qstr *qname, struct smb_fattr *entry);
+/* sock.c */
+extern int smb_valid_socket(struct inode *inode);
+extern int smb_catch_keepalive(struct smb_sb_info *server);
+extern int smb_dont_catch_keepalive(struct smb_sb_info *server);
+extern void smb_close_socket(struct smb_sb_info *server);
+extern int smb_round_length(int len);
+extern int smb_request(struct smb_sb_info *server);
+extern int smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command, int ldata, unsigned char *data, int lparam, unsigned char *param, int *lrdata, unsigned char **rdata, int *lrparam, unsigned char **rparam);
+/* inode.c */
+extern struct inode *smb_iget(struct super_block *sb, struct smb_fattr *fattr);
+extern void smb_get_inode_attr(struct inode *inode, struct smb_fattr *fattr);
+extern void smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr);
+extern void smb_invalidate_inodes(struct smb_sb_info *server);
+extern int smb_revalidate_inode(struct dentry *dentry);
+extern struct super_block *smb_read_super(struct super_block *sb, void *raw_data, int silent);
+extern int smb_notify_change(struct dentry *dentry, struct iattr *attr);
+/* file.c */
+extern struct address_space_operations smb_file_aops;
+extern struct file_operations smb_file_operations;
+extern struct inode_operations smb_file_inode_operations;
+/* ioctl.c */
+extern int smb_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
diff -urN linux-2.4.11-pre2/fs/smbfs/sock.c linux/fs/smbfs/sock.c
--- linux-2.4.11-pre2/fs/smbfs/sock.c	Tue May 15 13:40:55 2001
+++ linux/fs/smbfs/sock.c	Mon Dec  3 23:15:40 2001
@@ -27,6 +27,7 @@
 #include <asm/uaccess.h>
 
 #include "smb_debug.h"
+#include "proto.h"
 
 
 static int
@@ -674,7 +675,7 @@
 	 */
 	if (server->rcls) {
 		int error = smb_errno(server);
-		if (error == EBADSLT) {
+		if (error == -EBADSLT) {
 			printk(KERN_ERR "smb_request: tree ID invalid\n");
 			result = error;
 			goto bad_conn;
@@ -866,7 +867,7 @@
 	 */
 	if (server->rcls) {
 		int error = smb_errno(server);
-		if (error == EBADSLT) {
+		if (error == -EBADSLT) {
 			printk(KERN_ERR "smb_request: tree ID invalid\n");
 			result = error;
 			goto bad_conn;
diff -urN linux-2.4.11-pre2/fs/super.c linux/fs/super.c
--- linux-2.4.11-pre2/fs/super.c	Sat Sep 22 20:35:43 2001
+++ linux/fs/super.c	Mon Dec  3 23:15:40 2001
@@ -280,6 +280,7 @@
 }
 
 static LIST_HEAD(vfsmntlist);
+static struct vfsmount *root_vfsmnt;
 
 static struct list_head *mount_hashtable;
 static int hash_mask, hash_bits;
@@ -326,6 +327,15 @@
 	return p;
 }
 
+static int check_mnt(struct vfsmount *mnt)
+{
+	spin_lock(&dcache_lock);
+	while (mnt->mnt_parent != mnt)
+		mnt = mnt->mnt_parent;
+	spin_unlock(&dcache_lock);
+	return mnt == root_vfsmnt;
+}
+
 static void detach_mnt(struct vfsmount *mnt, struct nameidata *old_nd)
 {
 	old_nd->dentry = mnt->mnt_mountpoint;
@@ -346,50 +356,20 @@
 	nd->dentry->d_mounted++;
 }
 
-/**
- *	add_vfsmnt - add a new mount node
- *	@nd: location of mountpoint or %NULL if we want a root node
- *	@root: root of (sub)tree to be mounted
- *	@dev_name: device name to show in /proc/mounts or %NULL (for "none").
- *
- *	This is VFS idea of mount. New node is allocated, bound to a tree
- *	we are mounting and optionally (OK, usually) registered as mounted
- *	on a given mountpoint. Returns a pointer to new node or %NULL in
- *	case of failure.
- *
- *	Potential reason for failure (aside of trivial lack of memory) is a
- *	deleted mountpoint. Caller must hold ->i_zombie on mountpoint
- *	dentry (if any).
- */
-
-static struct vfsmount *add_vfsmnt(struct dentry *root, const char *dev_name)
+static struct vfsmount *next_mnt(struct vfsmount *p, struct vfsmount *root)
 {
-	struct vfsmount *mnt;
-	struct super_block *sb = root->d_inode->i_sb;
-	char *name;
-
-	mnt = alloc_vfsmnt();
-	if (!mnt)
-		goto out;
-
-	/* It may be NULL, but who cares? */
-	if (dev_name) {
-		name = kmalloc(strlen(dev_name)+1, GFP_KERNEL);
-		if (name) {
-			strcpy(name, dev_name);
-			mnt->mnt_devname = name;
+	struct list_head *next = p->mnt_mounts.next;
+	if (next == &p->mnt_mounts) {
+		while (1) {
+			if (p == root)
+				return NULL;
+			next = p->mnt_child.next;
+			if (next != &p->mnt_parent->mnt_mounts)
+				break;
+			p = p->mnt_parent;
 		}
 	}
-	mnt->mnt_sb = sb;
-	mnt->mnt_root = dget(root);
-	mnt->mnt_mountpoint = mnt->mnt_root;
-	mnt->mnt_parent = mnt;
-
-	spin_lock(&dcache_lock);
-	list_add(&mnt->mnt_list, vfsmntlist.prev);
-	spin_unlock(&dcache_lock);
-out:
-	return mnt;
+	return list_entry(next, struct vfsmount, mnt_child);
 }
 
 static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root)
@@ -447,37 +427,6 @@
 	return -ENOENT;
 }
 
-#ifdef CONFIG_BLK_DEV_INITRD
-static void move_vfsmnt(struct vfsmount *mnt,
-			struct nameidata *nd, 
-			const char *dev_name)
-{
-	struct nameidata parent_nd;
-	char *new_devname = NULL;
-
-	if (dev_name) {
-		new_devname = kmalloc(strlen(dev_name)+1, GFP_KERNEL);
-		if (new_devname)
-			strcpy(new_devname, dev_name);
-	}
-
-	spin_lock(&dcache_lock);
-	detach_mnt(mnt, &parent_nd);
-	attach_mnt(mnt, nd);
-
-	if (new_devname) {
-		if (mnt->mnt_devname)
-			kfree(mnt->mnt_devname);
-		mnt->mnt_devname = new_devname;
-	}
-	spin_unlock(&dcache_lock);
-
-	/* put the old stuff */
-	if (parent_nd.mnt != mnt)
-		path_release(&parent_nd);
-}
-#endif
-
 static void kill_super(struct super_block *);
 
 void __mntput(struct vfsmount *mnt)
@@ -1189,10 +1138,52 @@
 	return 0;
 }
 
+void umount_tree(struct vfsmount *mnt)
+{
+	struct vfsmount *p;
+	LIST_HEAD(kill);
+
+	if (list_empty(&mnt->mnt_list))
+		return;
+
+	for (p = mnt; p; p = next_mnt(p, mnt)) {
+		list_del(&p->mnt_list);
+		list_add(&p->mnt_list, &kill);
+	}
+
+	while (!list_empty(&kill)) {
+		mnt = list_entry(kill.next, struct vfsmount, mnt_list);
+		list_del_init(&mnt->mnt_list);
+		if (mnt->mnt_parent == mnt) {
+			spin_unlock(&dcache_lock);
+		} else {
+			struct nameidata old_nd;
+			detach_mnt(mnt, &old_nd);
+			spin_unlock(&dcache_lock);
+			path_release(&old_nd);
+		}
+		mntput(mnt);
+		spin_lock(&dcache_lock);
+	}
+}
+
 static int do_umount(struct vfsmount *mnt, int flags)
 {
 	struct super_block * sb = mnt->mnt_sb;
-	struct nameidata parent_nd;
+	int retval = 0;
+
+	/*
+	 * If we may have to abort operations to get out of this
+	 * mount, and they will themselves hold resources we must
+	 * allow the fs to do things. In the Unix tradition of
+	 * 'Gee thats tricky lets do it in userspace' the umount_begin
+	 * might fail to complete on the first run through as other tasks
+	 * must return, and the like. Thats for the mount program to worry
+	 * about for the moment.
+	 */
+
+	if( (flags&MNT_FORCE) && sb->s_op->umount_begin)
+		sb->s_op->umount_begin(sb);
 
 	/*
 	 * No sense to grab the lock for this test, but test itself looks
@@ -1204,7 +1195,7 @@
 	 * /reboot - static binary that would close all descriptors and
 	 * call reboot(9). Then init(8) could umount root and exec /reboot.
 	 */
-	if (mnt == current->fs->rootmnt) {
+	if (mnt == current->fs->rootmnt && !(flags & MNT_DETACH)) {
 		int retval = 0;
 		/*
 		 * Special case for "unmounting" root ...
@@ -1220,59 +1211,20 @@
 
 	spin_lock(&dcache_lock);
 
-	if (atomic_read(&sb->s_active) > 1) {
-		if (atomic_read(&mnt->mnt_count) > 2) {
-			spin_unlock(&dcache_lock);
-			return -EBUSY;
-		}
-		detach_mnt(mnt, &parent_nd);
-		list_del(&mnt->mnt_list);
+	if (atomic_read(&sb->s_active) == 1) {
+		/* last instance - try to be smart */
 		spin_unlock(&dcache_lock);
-		mntput(mnt);
-		if (parent_nd.mnt != mnt)
-			path_release(&parent_nd);
-		return 0;
+		DQUOT_OFF(sb);
+		acct_auto_close(sb->s_dev);
+		spin_lock(&dcache_lock);
 	}
-	spin_unlock(&dcache_lock);
-
-	/*
-	 * Before checking whether the filesystem is still busy,
-	 * make sure the kernel doesn't hold any quota files open
-	 * on the device. If the umount fails, too bad -- there
-	 * are no quotas running any more. Just turn them on again.
-	 */
-	DQUOT_OFF(sb);
-	acct_auto_close(sb->s_dev);
-
-	/*
-	 * If we may have to abort operations to get out of this
-	 * mount, and they will themselves hold resources we must
-	 * allow the fs to do things. In the Unix tradition of
-	 * 'Gee thats tricky lets do it in userspace' the umount_begin
-	 * might fail to complete on the first run through as other tasks
-	 * must return, and the like. Thats for the mount program to worry
-	 * about for the moment.
-	 */
-
-	if( (flags&MNT_FORCE) && sb->s_op->umount_begin)
-		sb->s_op->umount_begin(sb);
-
-	/* Something might grab it again - redo checks */
-
-	spin_lock(&dcache_lock);
-	if (atomic_read(&mnt->mnt_count) > 2) {
-		spin_unlock(&dcache_lock);
-		return -EBUSY;
+	retval = -EBUSY;
+	if (atomic_read(&mnt->mnt_count) == 2 || flags & MNT_DETACH) {
+		umount_tree(mnt);
+		retval = 0;
 	}
-
-	/* OK, that's the point of no return */
-	detach_mnt(mnt, &parent_nd);
-	list_del(&mnt->mnt_list);
 	spin_unlock(&dcache_lock);
-	mntput(mnt);
-	if (parent_nd.mnt != mnt)
-		path_release(&parent_nd);
-	return 0;
+	return retval;
 }
 
 /*
@@ -1302,6 +1254,8 @@
 	retval = -EINVAL;
 	if (nd.dentry != nd.mnt->mnt_root)
 		goto dput_and_out;
+	if (!check_mnt(nd.mnt))
+		goto dput_and_out;
 
 	retval = -EPERM;
 	if (!capable(CAP_SYS_ADMIN) && current->uid!=nd.mnt->mnt_owner)
@@ -1353,7 +1307,7 @@
 static int do_loopback(struct nameidata *nd, char *old_name)
 {
 	struct nameidata old_nd;
-	struct vfsmount *mnt;
+	struct vfsmount *mnt = NULL;
 	int err;
 
 	err = mount_is_safe(nd);
@@ -1369,12 +1323,16 @@
 		return err;
 
 	down(&mount_sem);
-	err = -ENOMEM;
-	mnt = clone_mnt(old_nd.mnt, old_nd.dentry);
+	err = -EINVAL;
+	if (check_mnt(nd->mnt)) {
+		err = -ENOMEM;
+		mnt = clone_mnt(old_nd.mnt, old_nd.dentry);
+	}
 	if (mnt) {
 		err = graft_tree(mnt, nd);
 		mntput(mnt);
 	}
+
 	up(&mount_sem);
 	path_release(&old_nd);
 	return err;
@@ -1394,6 +1352,9 @@
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
+	if (!check_mnt(nd->mnt))
+		return -EINVAL;
+
 	if (nd->dentry != nd->mnt->mnt_root)
 		return -EINVAL;
 
@@ -1472,27 +1433,31 @@
 			int mnt_flags, char *name, void *data)
 {
 	struct vfsmount *mnt = do_kern_mount(type, flags, name, data);
-	int retval = PTR_ERR(mnt);
+	int err = PTR_ERR(mnt);
 
 	if (IS_ERR(mnt))
 		goto out;
 
-	mnt->mnt_flags = mnt_flags;
-
 	down(&mount_sem);
 	/* Something was mounted here while we slept */
 	while(d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry))
 		;
+	err = -EINVAL;
+	if (!check_mnt(nd->mnt))
+		goto unlock;
 
 	/* Refuse the same filesystem on the same mount point */
+	err = -EBUSY;
 	if (nd->mnt->mnt_sb == mnt->mnt_sb && nd->mnt->mnt_root == nd->dentry)
-		retval = -EBUSY;
-	else
-		retval = graft_tree(mnt, nd);
+		goto unlock;
+
+	mnt->mnt_flags = mnt_flags;
+	err = graft_tree(mnt, nd);
+unlock:
 	up(&mount_sem);
 	mntput(mnt);
 out:
-	return retval;
+	return err;
 }
 
 static int copy_mount_options (const void *data, unsigned long *where)
@@ -1630,6 +1595,7 @@
 
 void __init mount_root(void)
 {
+	struct nameidata root_nd;
 	struct file_system_type * fs_type;
 	struct super_block * sb;
 	struct vfsmount *vfsmnt;
@@ -1639,6 +1605,7 @@
 	void *handle;
 	char path[64];
 	int path_start = -1;
+	char *name = "/dev/root";
 
 #ifdef CONFIG_ROOT_NFS
 	void *data;
@@ -1776,13 +1743,26 @@
 		fs_type->name,
 		(sb->s_flags & MS_RDONLY) ? " readonly" : "");
 	if (path_start >= 0) {
+		name = path + path_start;
 		devfs_mk_symlink (NULL, "root", DEVFS_FL_DEFAULT,
-				  path + 5 + path_start, NULL, NULL);
-		memcpy (path + path_start, "/dev/", 5);
-		vfsmnt = add_vfsmnt(sb->s_root, path + path_start);
+				  name + 5, NULL, NULL);
+		memcpy (name, "/dev/", 5);
 	}
-	else
-		vfsmnt = add_vfsmnt(sb->s_root, "/dev/root");
+	vfsmnt = alloc_vfsmnt();
+	if (!vfsmnt)
+		panic("VFS: alloc_vfsmnt failed for root fs");
+
+	vfsmnt->mnt_devname = kmalloc(strlen(name)+1, GFP_KERNEL);
+	if (vfsmnt->mnt_devname)
+		strcpy(vfsmnt->mnt_devname, name);
+	vfsmnt->mnt_sb = sb;
+	vfsmnt->mnt_root = dget(sb->s_root);
+
+	root_nd.mnt = root_vfsmnt;
+	root_nd.dentry = root_vfsmnt->mnt_sb->s_root;
+	graft_tree(vfsmnt, &root_nd);
+	mntput(vfsmnt);
+
 	/* FIXME: if something will try to umount us right now... */
 	if (vfsmnt) {
 		set_fs_root(current->fs, vfsmnt, sb->s_root);
@@ -1791,10 +1771,8 @@
 			bdput(bdev); /* sb holds a reference */
 		return;
 	}
-	panic("VFS: add_vfsmnt failed for root fs");
 }
 
-
 static void chroot_fs_refs(struct dentry *old_root,
 			   struct vfsmount *old_rootmnt,
 			   struct dentry *new_root,
@@ -1836,10 +1814,8 @@
 
 asmlinkage long sys_pivot_root(const char *new_root, const char *put_old)
 {
-	struct dentry *root;
-	struct vfsmount *root_mnt;
 	struct vfsmount *tmp;
-	struct nameidata new_nd, old_nd, parent_nd, root_parent;
+	struct nameidata new_nd, old_nd, parent_nd, root_parent, user_nd;
 	char *name;
 	int error;
 
@@ -1858,11 +1834,14 @@
 	putname(name);
 	if (error)
 		goto out0;
+	error = -EINVAL;
+	if (!check_mnt(new_nd.mnt))
+		goto out1;
 
 	name = getname(put_old);
 	error = PTR_ERR(name);
 	if (IS_ERR(name))
-		goto out0;
+		goto out1;
 	error = 0;
 	if (path_init(name, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &old_nd))
 		error = path_walk(name, &old_nd);
@@ -1871,11 +1850,14 @@
 		goto out1;
 
 	read_lock(&current->fs->lock);
-	root_mnt = mntget(current->fs->rootmnt);
-	root = dget(current->fs->root);
+	user_nd.mnt = mntget(current->fs->rootmnt);
+	user_nd.dentry = dget(current->fs->root);
 	read_unlock(&current->fs->lock);
 	down(&mount_sem);
 	down(&old_nd.dentry->d_inode->i_zombie);
+	error = -EINVAL;
+	if (!check_mnt(user_nd.mnt))
+		goto out2;
 	error = -ENOENT;
 	if (IS_DEADDIR(new_nd.dentry->d_inode))
 		goto out2;
@@ -1884,10 +1866,10 @@
 	if (d_unhashed(old_nd.dentry) && !IS_ROOT(old_nd.dentry))
 		goto out2;
 	error = -EBUSY;
-	if (new_nd.mnt == root_mnt || old_nd.mnt == root_mnt)
+	if (new_nd.mnt == user_nd.mnt || old_nd.mnt == user_nd.mnt)
 		goto out2; /* loop */
 	error = -EINVAL;
-	if (root_mnt->mnt_root != root)
+	if (user_nd.mnt->mnt_root != user_nd.dentry)
 		goto out2;
 	if (new_nd.mnt->mnt_root != new_nd.dentry)
 		goto out2; /* not a mountpoint */
@@ -1906,22 +1888,18 @@
 	} else if (!is_subdir(old_nd.dentry, new_nd.dentry))
 		goto out3;
 	detach_mnt(new_nd.mnt, &parent_nd);
-	detach_mnt(root_mnt, &root_parent);
-	attach_mnt(root_mnt, &old_nd);
-	if (root_parent.mnt != root_mnt)
-		attach_mnt(new_nd.mnt, &root_parent);
+	detach_mnt(user_nd.mnt, &root_parent);
+	attach_mnt(user_nd.mnt, &old_nd);
+	attach_mnt(new_nd.mnt, &root_parent);
 	spin_unlock(&dcache_lock);
-	chroot_fs_refs(root,root_mnt,new_nd.dentry,new_nd.mnt);
+	chroot_fs_refs(user_nd.dentry,user_nd.mnt,new_nd.dentry,new_nd.mnt);
 	error = 0;
-	if (root_parent.mnt != root_mnt)
-		path_release(&root_parent);
-	if (parent_nd.mnt != new_nd.mnt)
-		path_release(&parent_nd);
+	path_release(&root_parent);
+	path_release(&parent_nd);
 out2:
 	up(&old_nd.dentry->d_inode->i_zombie);
 	up(&mount_sem);
-	dput(root);
-	mntput(root_mnt);
+	path_release(&user_nd);
 	path_release(&old_nd);
 out1:
 	path_release(&new_nd);
@@ -1940,8 +1918,13 @@
 {
 	struct vfsmount *old_rootmnt;
 	struct nameidata devfs_nd, nd;
+	struct nameidata parent_nd;
+	char *new_devname = kmalloc(strlen("/dev/root.old")+1, GFP_KERNEL);
 	int error = 0;
 
+	if (new_devname)
+		strcpy(new_devname, "/dev/root.old");
+
 	read_lock(&current->fs->lock);
 	old_rootmnt = mntget(current->fs->rootmnt);
 	read_unlock(&current->fs->lock);
@@ -1958,6 +1941,9 @@
 		} else 
 			path_release(&devfs_nd);
 	}
+	spin_lock(&dcache_lock);
+	detach_mnt(old_rootmnt, &parent_nd);
+	spin_unlock(&dcache_lock);
 	ROOT_DEV = new_root_dev;
 	mount_root();
 #if 1
@@ -1980,25 +1966,36 @@
 		blivet = blkdev_get(ramdisk, FMODE_READ, 0, BDEV_FS);
 		printk(KERN_NOTICE "Trying to unmount old root ... ");
 		if (!blivet) {
-			blivet = do_umount(old_rootmnt, 0);
+			spin_lock(&dcache_lock);
+			list_del(&old_rootmnt->mnt_list);
+ 			spin_unlock(&dcache_lock);
+ 			mntput(old_rootmnt);
 			mntput(old_rootmnt);
-			if (!blivet) {
-				int ioctl_err;
-
-				ioctl_err = ioctl_by_bdev(ramdisk, BLKFLSBUF, 0);
-				if (ioctl_err)
-					printk("failed to release ramdisk %d...", ioctl_err);
-				printk("okay\n");
-				error = 0;
-			}
+			blivet = ioctl_by_bdev(ramdisk, BLKFLSBUF, 0);
+			path_release(&parent_nd);
 			blkdev_put(ramdisk, BDEV_FS);
 		}
-		if (blivet)
+		if (blivet) {
 			printk(KERN_ERR "error %d\n", blivet);
+		} else {
+			printk("okay\n");
+			error = 0;
+		}			
+		kfree(new_devname);
 		return error;
 	}
-	/* FIXME: we should hold i_zombie on nd.dentry */
-	move_vfsmnt(old_rootmnt, &nd, "/dev/root.old");
+
+	spin_lock(&dcache_lock);
+	attach_mnt(old_rootmnt, &nd);
+	if (new_devname) {
+		if (old_rootmnt->mnt_devname)
+			kfree(old_rootmnt->mnt_devname);
+		old_rootmnt->mnt_devname = new_devname;
+	}
+	spin_unlock(&dcache_lock);
+
+	/* put the old stuff */
+	path_release(&parent_nd);
 	mntput(old_rootmnt);
 	path_release(&nd);
 	return 0;
@@ -2006,6 +2003,54 @@
 
 #endif
 
+/*
+ * Absolutely minimal fake fs - only empty root directory and nothing else.
+ * In 2.5 we'll use ramfs or tmpfs, but for now it's all we need - just
+ * something to go with root vfsmount.
+ */
+static struct dentry *rootfs_lookup(struct inode *dir, struct dentry *dentry)
+{
+	d_add(dentry, NULL);
+	return NULL;
+}
+static struct file_operations rootfs_dir_operations = {
+	read:		generic_read_dir,
+	readdir:	dcache_readdir,
+};
+static struct inode_operations rootfs_dir_inode_operations = {
+	lookup:		rootfs_lookup,
+};
+static struct super_block *rootfs_read_super(struct super_block * sb, void * data, int silent)
+{
+	struct inode * inode;
+	struct dentry * root;
+	static struct super_operations s_ops = {};
+	sb->s_op = &s_ops;
+	inode = new_inode(sb);
+	if (!inode)
+		return NULL;
+	inode->i_mode = S_IFDIR|0555;
+	inode->i_uid = inode->i_gid = 0;
+	inode->i_op = &rootfs_dir_inode_operations;
+	inode->i_fop = &rootfs_dir_operations;
+	root = d_alloc_root(inode);
+	if (!root) {
+		iput(inode);
+		return NULL;
+	}
+	sb->s_root = root;
+	return sb;
+}
+static DECLARE_FSTYPE(root_fs_type, "rootfs", rootfs_read_super, FS_NOMOUNT);
+
+static void __init init_mount_tree(void)
+{
+	register_filesystem(&root_fs_type);
+	root_vfsmnt = do_kern_mount("rootfs", 0, "rootfs", NULL);
+	if (IS_ERR(root_vfsmnt))
+		panic("can't allocate root vfsmount");
+}
+
 void __init mnt_init(unsigned long mempages)
 {
 	struct list_head *d;
@@ -2061,4 +2106,5 @@
 		d++;
 		i--;
 	} while (i);
+	init_mount_tree();
 }
diff -urN linux-2.4.11-pre2/include/asm-ppc/mmu_context.h linux/include/asm-ppc/mmu_context.h
--- linux-2.4.11-pre2/include/asm-ppc/mmu_context.h	Tue Aug 28 06:58:33 2001
+++ linux/include/asm-ppc/mmu_context.h	Mon Dec  3 23:15:40 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.mmu_context.h 1.15 08/16/01 23:00:17 paulus
+ * BK Id: SCCS/s.mmu_context.h 1.18 09/26/01 16:02:49 paulus
  */
 #ifdef __KERNEL__
 #ifndef __PPC_MMU_CONTEXT_H
@@ -29,7 +29,7 @@
  * of the 32-bit virtual address (the "effective segment ID") in order
  * to spread out the entries in the MMU hash table.  Note, if this
  * function is changed then arch/ppc/mm/hashtable.S will have to be
- * changed correspondly.
+ * changed to correspond.
  */
 #define CTX_TO_VSID(ctx, va)	(((ctx) * (897 * 16) + ((va) >> 28) * 0x111) \
 				 & 0xffffff)
@@ -89,7 +89,7 @@
  * Bitmap of contexts in use.
  * The size of this bitmap is LAST_CONTEXT + 1 bits.
  */
-extern unsigned long context_map[(LAST_CONTEXT+1) / (8*sizeof(unsigned long))];
+extern unsigned long context_map[];
 
 /*
  * This caches the next context number that we expect to be free.
diff -urN linux-2.4.11-pre2/include/linux/fs.h linux/include/linux/fs.h
--- linux-2.4.11-pre2/include/linux/fs.h	Mon Dec  3 23:15:30 2001
+++ linux/include/linux/fs.h	Mon Dec  3 23:15:40 2001
@@ -650,6 +650,7 @@
  */
 
 #define MNT_FORCE	0x00000001	/* Attempt to forcibily umount */
+#define MNT_DETACH	0x00000002	/* Just detach from the tree */
 
 #include <linux/minix_fs_sb.h>
 #include <linux/ext2_fs_sb.h>
diff -urN linux-2.4.11-pre2/include/linux/gameport.h linux/include/linux/gameport.h
--- linux-2.4.11-pre2/include/linux/gameport.h	Sun Sep 23 10:33:46 2001
+++ linux/include/linux/gameport.h	Mon Dec  3 23:15:40 2001
@@ -74,8 +74,8 @@
 void gameport_register_port(struct gameport *gameport);
 void gameport_unregister_port(struct gameport *gameport);
 #else
-void __inline__ gameport_register_port(struct gameport *gameport) { return; }
-void __inline__ gameport_unregister_port(struct gameport *gameport) { return; }
+static void __inline__ gameport_register_port(struct gameport *gameport) { return; }
+static void __inline__ gameport_unregister_port(struct gameport *gameport) { return; }
 #endif
 
 void gameport_register_device(struct gameport_dev *dev);
diff -urN linux-2.4.11-pre2/include/linux/genhd.h linux/include/linux/genhd.h
--- linux-2.4.11-pre2/include/linux/genhd.h	Sun Sep 23 10:32:42 2001
+++ linux/include/linux/genhd.h	Mon Dec  3 23:15:40 2001
@@ -13,23 +13,33 @@
 #include <linux/types.h>
 #include <linux/major.h>
 
+enum {
 /* These three have identical behaviour; use the second one if DOS fdisk gets
    confused about extended/logical partitions starting past cylinder 1023. */
-#define DOS_EXTENDED_PARTITION 5
-#define LINUX_EXTENDED_PARTITION 0x85
-#define WIN98_EXTENDED_PARTITION 0x0f
-
-#define LINUX_SWAP_PARTITION	0x82
-#define LINUX_RAID_PARTITION	0xfd	/* autodetect RAID partition */
-
-#ifdef CONFIG_SOLARIS_X86_PARTITION
-#define SOLARIS_X86_PARTITION	LINUX_SWAP_PARTITION
-#endif
-
-#define DM6_PARTITION		0x54	/* has DDO: use xlated geom & offset */
-#define EZD_PARTITION		0x55	/* EZ-DRIVE */
-#define DM6_AUX1PARTITION	0x51	/* no DDO:  use xlated geom */
-#define DM6_AUX3PARTITION	0x53	/* no DDO:  use xlated geom */
+	DOS_EXTENDED_PARTITION = 5,
+	LINUX_EXTENDED_PARTITION = 0x85,
+	WIN98_EXTENDED_PARTITION = 0x0f,
+
+	LINUX_SWAP_PARTITION = 0x82,
+	LINUX_RAID_PARTITION = 0xfd,	/* autodetect RAID partition */
+
+	SOLARIS_X86_PARTITION =	LINUX_SWAP_PARTITION,
+
+	DM6_PARTITION =	0x54,	/* has DDO: use xlated geom & offset */
+	EZD_PARTITION =	0x55,	/* EZ-DRIVE */
+	DM6_AUX1PARTITION = 0x51,	/* no DDO:  use xlated geom */
+	DM6_AUX3PARTITION = 0x53,	/* no DDO:  use xlated geom */
+
+	FREEBSD_PARTITION = 0xa5,    /* FreeBSD Partition ID */
+	OPENBSD_PARTITION = 0xa6,    /* OpenBSD Partition ID */
+	NETBSD_PARTITION = 0xa9,   /* NetBSD Partition ID */
+	BSDI_PARTITION = 0xb7,    /* BSDI Partition ID */
+/* Ours is not to wonder why.. */
+	BSD_PARTITION =	FREEBSD_PARTITION,
+	MINIX_PARTITION = 0x81,  /* Minix Partition ID */
+	UNIXWARE_PARTITION = 0x63,		/* Partition ID, same as */
+						/* GNU_HURD and SCO Unix */
+};
 
 struct partition {
 	unsigned char boot_ind;		/* 0x80 - active */
@@ -117,13 +127,6 @@
  * BSD disklabel support by Yossi Gottlieb <yogo@math.tau.ac.il>
  * updated by Marc Espie <Marc.Espie@openbsd.org>
  */
-#define FREEBSD_PARTITION	0xa5    /* FreeBSD Partition ID */
-#define OPENBSD_PARTITION	0xa6    /* OpenBSD Partition ID */
-#define NETBSD_PARTITION	0xa9    /* NetBSD Partition ID */
-#define BSDI_PARTITION		0xb7    /* BSDI Partition ID */
-
-/* Ours is not to wonder why.. */
-#define BSD_PARTITION		FREEBSD_PARTITION
 
 /* check against BSD src/sys/sys/disklabel.h for consistency */
 
@@ -182,8 +185,6 @@
  * and Krzysztof G. Baranowski <kgb@knm.org.pl>
  */
 
-#define UNIXWARE_PARTITION     0x63		/* Partition ID, same as */
-						/* GNU_HURD and SCO Unix */
 #define UNIXWARE_DISKMAGIC     (0xCA5E600DUL)	/* The disk magic number */
 #define UNIXWARE_DISKMAGIC2    (0x600DDEEEUL)	/* The slice table magic nr */
 #define UNIXWARE_NUMSLICE      16
@@ -233,7 +234,6 @@
 #endif /* CONFIG_UNIXWARE_DISKLABEL */
 
 #ifdef CONFIG_MINIX_SUBPARTITION
-#   define MINIX_PARTITION         0x81  /* Minix Partition ID */
 #   define MINIX_NR_SUBPARTITIONS  4
 #endif /* CONFIG_MINIX_SUBPARTITION */
 
diff -urN linux-2.4.11-pre2/include/linux/module.h linux/include/linux/module.h
--- linux-2.4.11-pre2/include/linux/module.h	Mon Dec  3 23:15:30 2001
+++ linux/include/linux/module.h	Mon Dec  3 23:15:40 2001
@@ -366,10 +366,10 @@
 
 #define __EXPORT_SYMBOL_GPL(sym, str)			\
 const char __kstrtab_##sym[]				\
-__attribute__((section(".kstrtab"))) = str;		\
-const struct module_symbol __ksymtab_GPLONLY_##sym	\
+__attribute__((section(".kstrtab"))) = "GPLONLY_" str;	\
+const struct module_symbol __ksymtab_##sym		\
 __attribute__((section("__ksymtab"))) =			\
-{ (unsigned long)&sym, __kstrtab_GPLONLY_##sym }
+{ (unsigned long)&sym, __kstrtab_##sym }
 
 #if defined(MODVERSIONS) || !defined(CONFIG_MODVERSIONS)
 #define EXPORT_SYMBOL(var)  __EXPORT_SYMBOL(var, __MODULE_STRING(var))
diff -urN linux-2.4.11-pre2/include/linux/smb_fs.h linux/include/linux/smb_fs.h
--- linux-2.4.11-pre2/include/linux/smb_fs.h	Wed Jun 20 16:07:57 2001
+++ linux/include/linux/smb_fs.h	Mon Dec  3 23:15:40 2001
@@ -161,84 +161,6 @@
 }
 
 
-/* FIXME! the prototype list is probably not correct. Automate? */
-
-/* linux/fs/smbfs/file.c */
-extern struct inode_operations smb_file_inode_operations;
-extern struct file_operations smb_file_operations;
-extern struct address_space_operations smb_file_aops;
-
-/* linux/fs/smbfs/dir.c */
-extern struct inode_operations smb_dir_inode_operations;
-extern struct file_operations smb_dir_operations;
-void smb_new_dentry(struct dentry *dentry);
-void smb_renew_times(struct dentry *);
-
-/* linux/fs/smbfs/ioctl.c */
-int smb_ioctl (struct inode *, struct file *, unsigned int, unsigned long);
-
-/* linux/fs/smbfs/inode.c */
-struct super_block *smb_read_super(struct super_block *, void *, int);
-void smb_get_inode_attr(struct inode *, struct smb_fattr *);
-void smb_set_inode_attr(struct inode *, struct smb_fattr *);
-void smb_invalidate_inodes(struct smb_sb_info *);
-int  smb_revalidate_inode(struct dentry *);
-int  smb_notify_change(struct dentry *, struct iattr *);
-struct inode *smb_iget(struct super_block *, struct smb_fattr *);
-
-/* linux/fs/smbfs/proc.c */
-int smb_setcodepage(struct smb_sb_info *server, struct smb_nls_codepage *cp);
-__u32 smb_len(unsigned char *);
-__u8 *smb_setup_header(struct smb_sb_info *, __u8, __u16, __u16);
-int smb_get_rsize(struct smb_sb_info *);
-int smb_get_wsize(struct smb_sb_info *);
-int smb_newconn(struct smb_sb_info *, struct smb_conn_opt *);
-int smb_errno(struct smb_sb_info *);
-int smb_close(struct inode *);
-int smb_close_fileid(struct dentry *, __u16);
-int smb_open(struct dentry *, int);
-int smb_proc_read(struct inode *, off_t, int, char *);
-int smb_proc_write(struct inode *, off_t, int, const char *);
-int smb_proc_create(struct dentry *, __u16, time_t, __u16 *);
-int smb_proc_mv(struct dentry *, struct dentry *);
-int smb_proc_mkdir(struct dentry *);
-int smb_proc_rmdir(struct dentry *);
-int smb_proc_unlink(struct dentry *);
-int smb_proc_readdir(struct file *filp, void *dirent, filldir_t filldir,
-		     struct smb_cache_control *ctl);
-int smb_proc_getattr(struct dentry *, struct smb_fattr *);
-int smb_proc_setattr(struct dentry *, struct smb_fattr *);
-int smb_proc_settime(struct dentry *, struct smb_fattr *);
-int smb_proc_dskattr(struct super_block *, struct statfs *);
-int smb_proc_disconnect(struct smb_sb_info *);
-int smb_proc_trunc(struct smb_sb_info *, __u16, __u32);
-int smb_proc_flush(struct smb_sb_info *, __u16);
-void smb_init_root_dirent(struct smb_sb_info *, struct smb_fattr *);
-
-/* linux/fs/smbfs/sock.c */
-int smb_round_length(int);
-int smb_valid_socket(struct inode *);
-void smb_close_socket(struct smb_sb_info *);
-int smb_request(struct smb_sb_info *server);
-int smb_catch_keepalive(struct smb_sb_info *server);
-int smb_dont_catch_keepalive(struct smb_sb_info *server);
-int smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command,
-		       int ldata, unsigned char *data,
-		       int lparam, unsigned char *param,
-		       int *lrdata, unsigned char **rdata,
-		       int *lrparam, unsigned char **rparam);
-
-/* fs/smbfs/cache.c */
-
-void smb_invalid_dir_cache(struct inode * dir);
-void smb_invalidate_dircache_entries(struct dentry *parent);
-struct dentry * smb_dget_fpos(struct dentry *dentry, struct dentry *parent, 
-			      unsigned long fpos);
-int smb_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
-		   struct smb_cache_control *ctrl, struct qstr *qname,
-		   struct smb_fattr *entry);
-
-
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_SMB_FS_H */
diff -urN linux-2.4.11-pre2/include/linux/smbno.h linux/include/linux/smbno.h
--- linux-2.4.11-pre2/include/linux/smbno.h	Mon Nov 24 10:30:40 1997
+++ linux/include/linux/smbno.h	Mon Dec  3 23:15:40 2001
@@ -39,7 +39,12 @@
 #define ERRbadshare 32          /* Share mode on file conflict with open mode */
 #define ERRlock 33              /* Lock request conflicts with existing lock */
 #define ERRfilexists 80         /* File in operation already exists */
-#define ERRundocumented1 123    /* Invalid name?? e.g. .tmp* */
+#define ERRinvalidparam 87      /* ERROR_INVALID_PARAMETER */
+#define ERRdiskfull 112         /* ERROR_DISK_FULL */
+#define ERRinvalidname 123      /* ERROR_INVALID_NAME */
+#define ERRdirnotempty 145      /* ERROR_DIR_NOT_EMPTY */
+#define ERRnotlocked 158        /* ERROR_NOT_LOCKED */
+#define ERRexists 183           /* ERROR_ALREADY_EXISTS, see also 80 */
 #define ERRbadpipe 230          /* Named pipe invalid */
 #define ERRpipebusy 231         /* All instances of pipe are busy */
 #define ERRpipeclosing 232      /* named pipe close in progress */
diff -urN linux-2.4.11-pre2/include/linux/spinlock.h linux/include/linux/spinlock.h
--- linux-2.4.11-pre2/include/linux/spinlock.h	Sun Sep 23 10:31:02 2001
+++ linux/include/linux/spinlock.h	Mon Dec  3 23:15:40 2001
@@ -42,6 +42,7 @@
 #if (DEBUG_SPINLOCKS < 1)
 
 #define atomic_dec_and_lock(atomic,lock) atomic_dec_and_test(atomic)
+#define ATOMIC_DEC_AND_LOCK
 
 /*
  * Your basic spinlocks, allowing only a single CPU anywhere
@@ -128,7 +129,7 @@
 #endif /* !SMP */
 
 /* "lock on reference count zero" */
-#ifndef atomic_dec_and_lock
+#ifndef ATOMIC_DEC_AND_LOCK
 #include <asm/atomic.h>
 extern int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock);
 #endif
diff -urN linux-2.4.11-pre2/init/main.c linux/init/main.c
--- linux-2.4.11-pre2/init/main.c	Mon Dec  3 23:15:30 2001
+++ linux/init/main.c	Mon Dec  3 23:15:40 2001
@@ -94,7 +94,6 @@
 extern void sysctl_init(void);
 extern void signals_init(void);
 extern int init_pcmcia_ds(void);
-extern void net_notifier_init(void);
 
 extern void free_initmem(void);
 
diff -urN linux-2.4.11-pre2/lib/dec_and_lock.c linux/lib/dec_and_lock.c
--- linux-2.4.11-pre2/lib/dec_and_lock.c	Tue Aug 28 07:11:33 2001
+++ linux/lib/dec_and_lock.c	Mon Dec  3 23:15:40 2001
@@ -26,7 +26,7 @@
  * store-conditional approach, for example.
  */
 
-#ifndef atomic_dec_and_lock
+#ifndef ATOMIC_DEC_AND_LOCK
 int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
 {
 	spin_lock(lock);
