diff -u --recursive --new-file v2.5.2/linux/CREDITS linux/CREDITS
--- v2.5.2/linux/CREDITS	Mon Jan 14 18:25:07 2002
+++ linux/CREDITS	Tue Jan 15 11:27:30 2002
@@ -588,6 +588,13 @@
 S: University of Michigan
 S: Ann Arbor, MI
 
+N: Michael Cornwell
+E: cornwell@acm.org
+D: Original designer and co-author of ATA Taskfile
+D: Kernel module SMART utilities
+S: Santa Cruz, California
+S: USA
+
 N: Kees Cook
 E: cook@cpoint.net
 W: http://outflux.net/
@@ -1186,22 +1193,19 @@
 
 N: Andre Hedrick
 E: andre@linux-ide.org
-E: andre@aslab.com
-E: andre@suse.com
+E: andre@linuxdiskcert.org
 W: http://www.linux-ide.org/
+W: http://www.linuxdiskcert.org/
 D: Random SMP kernel hacker...
 D: Uniform Multi-Platform E-IDE driver
 D: Active-ATA-Chipset maddness..........
-D: Ultra DMA 100/66/33
-D: ATA-Disconnect
+D: Ultra DMA 133/100/66/33 w/48-bit Addressing
+D: ATA-Disconnect, ATA-TCQ
 D: ATA-Smart Kernel Daemon
+D: Serial ATA
+D: ATA Command Block and Taskfile
 S: Linux ATA Development (LAD)
 S: Concord, CA
-S: ASL, Inc. 1-877-ASL-3535
-S: 1757 Houret Court, Milpitas, CA 95035
-S: SuSE Linux, Inc.
-S: 580 Second Street, Suite 210  Oakland, CA  94607
-S: USA
 
 N: Jochen Hein
 E: jochen@jochen.org
diff -u --recursive --new-file v2.5.2/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.5.2/linux/Documentation/Configure.help	Mon Jan 14 18:25:07 2002
+++ linux/Documentation/Configure.help	Tue Jan 15 10:56:35 2002
@@ -5949,32 +5949,6 @@
 
   If unsure, say N.
 
-Kernel/User network link driver
-CONFIG_NETLINK
-  This driver allows for two-way communication between the kernel and
-  user processes.  It does so by creating a new socket family,
-  PF_NETLINK.  Over this socket, the kernel can send and receive
-  datagrams carrying information.  It is documented on many systems in
-  netlink(7).
-
-  So far, the kernel uses this feature to publish some network related
-  information if you say Y to "Routing messages", below. You also need
-  to say Y here if you want to use arpd, a daemon that helps keep the
-  internal ARP cache (a mapping between IP addresses and hardware
-  addresses on the local network) small.  The ethertap device, which
-  lets user space programs read and write raw Ethernet frames, also
-  needs the network link driver.
-
-  If unsure, say Y.
-
-Routing messages
-CONFIG_RTNETLINK
-  If you say Y here, user space programs can receive some network
-  related routing information over the netlink. 'rtmon', supplied
-  with the iproute2 package (<ftp://ftp.inr.ac.ru/>), can read and
-  interpret this data.  Information sent to the kernel over this link
-  is ignored.
-
 Netlink device emulation
 CONFIG_NETLINK_DEV
   This option will be removed soon. Any programs that want to use
@@ -24048,6 +24022,16 @@
   kernel tree does. Such modules that use library CRC32 functions
   require M here.
 
+802.1Q VLAN Support
+CONFIG_VLAN_8021Q
+  Select this and you will be able to create 802.1Q VLAN interfaces on your
+  ethernet interfaces.  802.1Q VLAN supports almost everything a regular
+  ethernet interface does, including firewalling, bridging, and of course
+  IP traffic.  You will need the 'vconfig' tool from the VLAN project in
+  order to effectively use VLANs.  See the VLAN web page for more
+  information:  http://www.candelatech.com/~greear/vlan.html  If unsure,
+  you can safely say 'N'.
+
 #
 # A couple of things I keep forgetting:
 #   capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet,
@@ -24097,10 +24081,10 @@
 # LocalWords:  filesystems smbfs ATA ppp PCTech RZ www powerquest txt CMD ESDI
 # LocalWords:  chipset FB multicast MROUTE appletalk ifconfig IBMTR multiport
 # LocalWords:  Multisession STALDRV EasyIO EC EasyConnection ISTALLION ONboard
-# LocalWords:  Brumby pci TNC cis ohio faq usenet NETLINK dev hydra ca Tyne mem
+# LocalWords:  Brumby pci TNC cis ohio faq usenet dev hydra ca Tyne mem
 # LocalWords:  carleton DECstation SUNFD JENSEN Noname XXXM SLiRP LILO's amifb
 # LocalWords:  pppd Zilog ZS SRM bootloader ez mainmenu rarp ipfwadm paride pcd
-# LocalWords:  RTNETLINK mknod xos MTU lwared Macs netatalk macs cs Wolff
+# LocalWords:  mknod xos MTU lwared Macs netatalk macs cs Wolff
 # LocalWords:  dartmouth flowerpt MultiMaster FlashPoint tudelft etherexpress
 # LocalWords:  ICL EtherTeam ETH IDESCSI TXC SmartRAID SmartCache httpd sjc dlp
 # LocalWords:  thesphere TwoServers BOOTP DHCP ncpfs BPQETHER BPQ MG HIPPI cern
diff -u --recursive --new-file v2.5.2/linux/Documentation/DMA-mapping.txt linux/Documentation/DMA-mapping.txt
--- v2.5.2/linux/Documentation/DMA-mapping.txt	Fri Oct 12 15:35:53 2001
+++ linux/Documentation/DMA-mapping.txt	Tue Jan 15 11:48:13 2002
@@ -60,6 +60,9 @@
 might be mapped somewhere entirely different than the rest of physical
 memory.
 
+Also, this means that you cannot take the return of a kmap()
+call and DMA to/from that.  This is similar to vmalloc().
+
 What about block I/O and networking buffers?  The block I/O and
 networking subsystems make sure that the buffers they use are valid
 for you to DMA from/to.
@@ -685,6 +688,97 @@
 
 This is possible with the DAC interfaces purely because they are
 not translated in any way.
+
+		Optimizing Unmap State Space Consumption
+
+On many platforms, pci_unmap_{single,page}() is simply a nop.
+Therefore, keeping track of the mapping address and length is a waste
+of space.  Instead of filling your drivers up with ifdefs and the like
+to "work around" this (which would defeat the whole purpose of a
+portable API) the following facilities are provided.
+
+Actually, instead of describing the macros one by one, we'll
+transform some example code.
+
+1) Use DECLARE_PCI_UNMAP_{ADDR,LEN} in state saving structures.
+   Example, before:
+
+	struct ring_state {
+		struct sk_buff *skb;
+		dma_addr_t mapping;
+		__u32 len;
+	};
+
+   after:
+
+	struct ring_state {
+		struct sk_buff *skb;
+		DECLARE_PCI_UNMAP_ADDR(mapping)
+		DECLARE_PCI_UNMAP_LEN(len)
+	};
+
+   NOTE: DO NOT put a semicolon at the end of the DECLARE_*()
+         macro.
+
+2) Use pci_unmap_{addr,len}_set to set these values.
+   Example, before:
+
+	ringp->mapping = FOO;
+	ringp->len = BAR;
+
+   after:
+
+	pci_unmap_addr_set(ringp, mapping, FOO);
+	pci_unmap_len_set(ringp, len, BAR);
+
+3) Use pci_unmap_{addr,len} to access these values.
+   Example, before:
+
+	pci_unmap_single(pdev, ringp->mapping, ringp->len,
+			 PCI_DMA_FROMDEVICE);
+
+   after:
+
+	pci_unmap_single(pdev,
+			 pci_unmap_addr(ringp, mapping),
+			 pci_unmap_len(ringp, len),
+			 PCI_DMA_FROMDEVICE);
+
+It really should be self-explanatory.  We treat the ADDR and LEN
+seperately, because it is possible for an implementation to only
+need the address in order to perform the unmap operation.
+
+			Platform Issues
+
+If you are just writing drivers for Linux and do not maintain
+an architecture port for the kernel, you can safely skip down
+to "Closing".
+
+1) Struct scatterlist requirements.
+
+   Struct scatterlist must contain, at a minimum, the following
+   members:
+
+	char *address;
+	struct page *page;
+	unsigned int offset;
+	unsigned int length;
+
+   The "address" member will disappear in 2.5.x
+
+   This means that your pci_{map,unmap}_sg() and all other
+   interfaces dealing with scatterlists must be able to cope
+   properly with page being non NULL.
+
+   A scatterlist is in one of two states.  The base address is
+   either specified by "address" or by a "page+offset" pair.
+   If "address" is NULL, then "page+offset" is being used.
+   If "page" is NULL, then "address" is being used.
+
+   In 2.5.x, all scatterlists will use "page+offset".  But during
+   2.4.x we still have to support the old method.
+
+2) More to come...
 
 			   Closing
 
diff -u --recursive --new-file v2.5.2/linux/Documentation/DocBook/kernel-hacking.tmpl linux/Documentation/DocBook/kernel-hacking.tmpl
--- v2.5.2/linux/Documentation/DocBook/kernel-hacking.tmpl	Mon Jan 14 18:25:07 2002
+++ linux/Documentation/DocBook/kernel-hacking.tmpl	Tue Jan 15 13:53:50 2002
@@ -371,8 +371,7 @@
   </para>
 
   <programlisting>
-if (current-&gt;need_resched)
-        schedule(); /* Will sleep */ 
+cond_resched(); /* Will sleep */ 
   </programlisting>
 
   <para>
diff -u --recursive --new-file v2.5.2/linux/Documentation/cachetlb.txt linux/Documentation/cachetlb.txt
--- v2.5.2/linux/Documentation/cachetlb.txt	Sun Oct 21 10:40:36 2001
+++ linux/Documentation/cachetlb.txt	Tue Jan 15 10:56:35 2002
@@ -49,17 +49,18 @@
 	page table operations such as what happens during
 	fork, and exec.
 
-3) void flush_tlb_range(struct mm_struct *mm,
+3) void flush_tlb_range(struct vm_area_struct *vma,
 			unsigned long start, unsigned long end)
 
 	Here we are flushing a specific range of (user) virtual
 	address translations from the TLB.  After running, this
 	interface must make sure that any previous page table
-	modifications for the address space 'mm' in the range 'start'
-	to 'end' will be visible to the cpu.  That is, after running,
-	there will be no entries in the TLB for 'mm' for virtual
-	addresses in the range 'start' to 'end'.
+	modifications for the address space 'vma->vm_mm' in the range
+	'start' to 'end' will be visible to the cpu.  That is, after
+	running, here will be no entries in the TLB for 'mm' for
+	virtual addresses in the range 'start' to 'end'.
 
+	The "vma" is the backing store being used for the region.
 	Primarily, this is used for munmap() type operations.
 
 	The interface is provided in hopes that the port can find
@@ -130,9 +131,9 @@
 	   change_all_page_tables_of(mm);
 	   flush_tlb_mm(mm);
 
-	2) flush_cache_range(mm, start, end);
+	2) flush_cache_range(vma, start, end);
 	   change_range_of_page_tables(mm, start, end);
-	   flush_tlb_range(mm, start, end);
+	   flush_tlb_range(vma, start, end);
 
 	3) flush_cache_page(vma, page);
 	   set_pte(pte_pointer, new_pte_val);
@@ -173,14 +174,15 @@
 	page table operations such as what happens during
 	fork, exit, and exec.
 
-3) void flush_cache_range(struct mm_struct *mm,
+3) void flush_cache_range(struct vm_area_struct *vma,
 			  unsigned long start, unsigned long end)
 
 	Here we are flushing a specific range of (user) virtual
 	addresses from the cache.  After running, there will be no
-	entries in the cache for 'mm' for virtual addresses in the
-	range 'start' to 'end'.
+	entries in the cache for 'vma->vm_mm' for virtual addresses in
+	the range 'start' to 'end'.
 
+	The "vma" is the backing store being used for the region.
 	Primarily, this is used for munmap() type operations.
 
 	The interface is provided in hopes that the port can find
@@ -275,7 +277,7 @@
 	for example, uses this technique.
 
 	The "address" parameter tells the virtual address where the
-	user will ultimately this page mapped.
+	user will ultimately have this page mapped.
 
 	If D-cache aliasing is not an issue, these two routines may
 	simply call memcpy/memset directly and do nothing more.
diff -u --recursive --new-file v2.5.2/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt
--- v2.5.2/linux/Documentation/ioctl-number.txt	Wed Jul 11 16:35:37 2001
+++ linux/Documentation/ioctl-number.txt	Thu Jan 17 14:06:53 2002
@@ -101,7 +101,8 @@
 'S'	82-FF	scsi/scsi.h		conflict!
 'T'	all	linux/soundcard.h	conflict!
 'T'	all	asm-i386/ioctls.h	conflict!
-'U'	all	linux/drivers/usb/usb.h
+'U'	00-EF	linux/drivers/usb/usb.h
+'U'	F0-FF	drivers/usb/auerswald.c
 'V'	all	linux/vt.h
 'W'	00-1F	linux/watchdog.h	conflict!
 'W'	00-1F	linux/wanrouter.h	conflict!
diff -u --recursive --new-file v2.5.2/linux/Documentation/networking/decnet.txt linux/Documentation/networking/decnet.txt
--- v2.5.2/linux/Documentation/networking/decnet.txt	Fri Feb 16 15:53:08 2001
+++ linux/Documentation/networking/decnet.txt	Tue Jan 15 10:56:35 2002
@@ -4,20 +4,9 @@
 1) Other documentation....
 
    o Project Home Pages
-       http://www.sucs.swan.ac.uk/~rohan/DECnet/index.html - Kernel info
+       http://www.chygwyn.com/DECnet/                      - Kernel info
        http://linux-decnet.sourceforge.net/                - Userland tools
-
-   o FTP sites
-       ftp://ftp.sucs.swan.ac.uk/pub/Linux/DECnet/
-                - Swansea University Computer Society DECnet Archive
-                  (contains kernel patches and info)
-                - Mirror of userland tools on ftp.dreamtime.org
-                - Mirror of Alexey Kuznetsov's iproute2 package and
-                  other utilities
-
-       ftp://linux-decnet.sourceforge.net/pub/linux-decnet/ 
-                - Patrick Caulfield's archive of userland tools and
-                  Eduardo Serrat's kernel patches
+       http://www.sourceforge.net/projects/linux-decnet/   - Status page
 
 2) Configuring the kernel
 
@@ -31,9 +20,13 @@
 you'll need the following options as well...
 
     CONFIG_DECNET_ROUTER (to be able to add/delete routes)
-    CONFIG_NETLINK (to allow rtnetlink)
-    CONFIG_RTNETLINK (for communication with the kernel routing layer)
     CONFIG_NETFILTER (will be required for the DECnet routing daemon)
+
+    CONFIG_DECNET_ROUTE_FWMARK is optional
+
+Don't turn on SIOCGIFCONF support for DECnet unless you are really sure
+that you need it, in general you won't and it can cause ifconfig to
+malfunction.
 
 3) Command line options
 
diff -u --recursive --new-file v2.5.2/linux/MAINTAINERS linux/MAINTAINERS
--- v2.5.2/linux/MAINTAINERS	Mon Jan 14 18:25:07 2002
+++ linux/MAINTAINERS	Tue Jan 15 11:27:30 2002
@@ -700,12 +700,12 @@
 IDE DRIVER [GENERAL]
 P:	Andre Hedrick
 M:	andre@linux-ide.org
-M:	andre@aslab.com
-M:	andre@suse.com
+M:	andre@linuxdiskcert.org
 L:	linux-kernel@vger.kernel.org
 W:	http://www.kernel.org/pub/linux/kernel/people/hedrick/
 W:	http://www.linux-ide.org/
-S:	Supported
+W:	http://www.linuxdiskcert.org/
+S:	Maintained
 
 IDE/ATAPI CDROM DRIVER
 P:	Jens Axboe
diff -u --recursive --new-file v2.5.2/linux/Makefile linux/Makefile
--- v2.5.2/linux/Makefile	Mon Jan 14 18:25:07 2002
+++ linux/Makefile	Wed Jan 16 11:14:10 2002
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 5
-SUBLEVEL = 2
-EXTRAVERSION =
+SUBLEVEL = 3
+EXTRAVERSION =-pre2
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -u --recursive --new-file v2.5.2/linux/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c
--- v2.5.2/linux/arch/alpha/kernel/smp.c	Mon Jan 14 18:25:07 2002
+++ linux/arch/alpha/kernel/smp.c	Tue Jan 15 10:56:35 2002
@@ -1048,10 +1048,10 @@
 }
 
 void
-flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
 	/* On the Alpha we always flush the whole user tlb.  */
-	flush_tlb_mm(mm);
+	flush_tlb_mm(vma->vm_mm);
 }
 
 static void
diff -u --recursive --new-file v2.5.2/linux/arch/arm/kernel/ecard.c linux/arch/arm/kernel/ecard.c
--- v2.5.2/linux/arch/arm/kernel/ecard.c	Sun Aug 12 11:13:59 2001
+++ linux/arch/arm/kernel/ecard.c	Fri Jan 18 16:17:45 2002
@@ -243,6 +243,8 @@
  */
 static void ecard_init_pgtables(struct mm_struct *mm)
 {
+	struct vm_area_struct vma;
+
 	/* We want to set up the page tables for the following mapping:
 	 *  Virtual	Physical
 	 *  0x03000000	0x03000000
@@ -274,8 +276,10 @@
 		dst_addr += PGDIR_SIZE;
 	}
 
-	flush_tlb_range(mm, IO_START, IO_START + IO_SIZE);
-	flush_tlb_range(mm, EASI_START, EASI_START + EASI_SIZE);
+	vma.vm_mm = mm;
+
+	flush_tlb_range(&vma, IO_START, IO_START + IO_SIZE);
+	flush_tlb_range(&vma, EASI_START, EASI_START + EASI_SIZE);
 }
 
 static int ecard_init_mm(void)
diff -u --recursive --new-file v2.5.2/linux/arch/arm/kernel/init_task.c linux/arch/arm/kernel/init_task.c
--- v2.5.2/linux/arch/arm/kernel/init_task.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/arm/kernel/init_task.c	Tue Jan 15 11:06:55 2002
@@ -5,6 +5,7 @@
 #include <linux/fs.h>
 #include <linux/sched.h>
 #include <linux/init.h>
+#include <linux/init_task.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v2.5.2/linux/arch/arm/kernel/process.c linux/arch/arm/kernel/process.c
--- v2.5.2/linux/arch/arm/kernel/process.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/arm/kernel/process.c	Tue Jan 15 13:53:50 2002
@@ -91,7 +91,7 @@
 		if (!idle)
 			idle = arch_idle;
 		leds_event(led_idle_start);
-		while (!current->need_resched)
+		while (!need_resched())
 			idle();
 		leds_event(led_idle_end);
 		schedule();
diff -u --recursive --new-file v2.5.2/linux/arch/cris/mm/tlb.c linux/arch/cris/mm/tlb.c
--- v2.5.2/linux/arch/cris/mm/tlb.c	Thu Jul 26 15:10:06 2001
+++ linux/arch/cris/mm/tlb.c	Tue Jan 15 10:56:35 2002
@@ -159,10 +159,11 @@
 /* invalidate a page range */
 
 void
-flush_tlb_range(struct mm_struct *mm, 
+flush_tlb_range(struct vm_area_struct *vma,
 		unsigned long start,
 		unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
 	int page_id = mm->context;
 	int i;
 	unsigned long flags;
diff -u --recursive --new-file v2.5.2/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.5.2/linux/arch/i386/defconfig	Mon Jan 14 18:25:08 2002
+++ linux/arch/i386/defconfig	Tue Jan 15 11:46:20 2002
@@ -154,7 +154,7 @@
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK is not set
+# CONFIG_NETLINK_DEV is not set
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
 CONFIG_UNIX=y
@@ -205,6 +205,7 @@
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_BLK_DEV_IDEDISK=y
 CONFIG_IDEDISK_MULTI_MODE=y
+# CONFIG_IDEDISK_STROKE is not set
 # CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
 # CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
 # CONFIG_BLK_DEV_IDEDISK_IBM is not set
@@ -219,6 +220,7 @@
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
+CONFIG_IDE_TASK_IOCTL=y
 
 #
 # IDE chipset support/bugfixes
@@ -230,12 +232,15 @@
 CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
-CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
 CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
@@ -252,6 +257,7 @@
 CONFIG_PIIX_TUNING=y
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PDC_ADMA is not set
 # CONFIG_BLK_DEV_PDC202XX is not set
 # CONFIG_PDC202XX_BURST is not set
 # CONFIG_PDC202XX_FORCE is not set
diff -u --recursive --new-file v2.5.2/linux/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c
--- v2.5.2/linux/arch/i386/kernel/apm.c	Tue Dec 18 14:56:34 2001
+++ linux/arch/i386/kernel/apm.c	Tue Jan 15 13:53:50 2002
@@ -766,14 +766,14 @@
 
 	start_idle = jiffies;
 	while (1) {
-		if (!current->need_resched) {
+		if (!need_resched()) {
 			if (jiffies - start_idle < HARD_IDLE_TIMEOUT) {
 				if (!current_cpu_data.hlt_works_ok)
 					continue;
 				if (hlt_counter)
 					continue;
 				__cli();
-				if (!current->need_resched)
+				if (!need_resched())
 					safe_halt();
 				else
 					__sti();
diff -u --recursive --new-file v2.5.2/linux/arch/i386/kernel/init_task.c linux/arch/i386/kernel/init_task.c
--- v2.5.2/linux/arch/i386/kernel/init_task.c	Mon Sep 17 15:29:09 2001
+++ linux/arch/i386/kernel/init_task.c	Tue Jan 15 11:06:55 2002
@@ -1,6 +1,7 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/init.h>
+#include <linux/init_task.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v2.5.2/linux/arch/i386/kernel/pci-i386.c linux/arch/i386/kernel/pci-i386.c
--- v2.5.2/linux/arch/i386/kernel/pci-i386.c	Sun Nov  4 09:31:58 2001
+++ linux/arch/i386/kernel/pci-i386.c	Tue Jan 15 10:56:35 2002
@@ -375,7 +375,7 @@
 	/* Write-combine setting is ignored, it is changed via the mtrr
 	 * interfaces on this platform.
 	 */
-	if (remap_page_range(vma->vm_start, vma->vm_pgoff << PAGE_SHIFT,
+	if (remap_page_range(vma, vma->vm_start, vma->vm_pgoff << PAGE_SHIFT,
 			     vma->vm_end - vma->vm_start,
 			     vma->vm_page_prot))
 		return -EAGAIN;
diff -u --recursive --new-file v2.5.2/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v2.5.2/linux/arch/i386/kernel/process.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/i386/kernel/process.c	Tue Jan 15 14:33:55 2002
@@ -42,7 +42,6 @@
 #include <asm/processor.h>
 #include <asm/i387.h>
 #include <asm/desc.h>
-#include <asm/mmu_context.h>
 #ifdef CONFIG_MATH_EMULATION
 #include <asm/math_emu.h>
 #endif
@@ -81,7 +80,7 @@
 {
 	if (current_cpu_data.hlt_works_ok && !hlt_counter) {
 		__cli();
-		if (!current->need_resched)
+		if (!need_resched())
 			safe_halt();
 		else
 			__sti();
@@ -127,7 +126,7 @@
 		void (*idle)(void) = pm_idle;
 		if (!idle)
 			idle = default_idle;
-		while (!current->need_resched)
+		while (!need_resched())
 			idle();
 		schedule();
 		check_pgt_cache();
diff -u --recursive --new-file v2.5.2/linux/arch/i386/math-emu/fpu_entry.c linux/arch/i386/math-emu/fpu_entry.c
--- v2.5.2/linux/arch/i386/math-emu/fpu_entry.c	Fri Apr  6 10:42:47 2001
+++ linux/arch/i386/math-emu/fpu_entry.c	Tue Jan 15 13:53:50 2002
@@ -559,7 +559,7 @@
   RE_ENTRANT_CHECK_ON;
 #endif /* DEBUG */
 
-  if (FPU_lookahead && !current->need_resched)
+  if (FPU_lookahead && !need_resched())
     {
       FPU_ORIG_EIP = FPU_EIP - code_base;
       if ( valid_prefix(&byte1, (u_char **)&FPU_EIP,
diff -u --recursive --new-file v2.5.2/linux/arch/ia64/kernel/init_task.c linux/arch/ia64/kernel/init_task.c
--- v2.5.2/linux/arch/ia64/kernel/init_task.c	Mon Sep 17 15:29:09 2001
+++ linux/arch/ia64/kernel/init_task.c	Tue Jan 15 11:06:55 2002
@@ -9,6 +9,7 @@
 #include <linux/init.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
+#include <linux/init_task.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v2.5.2/linux/arch/ia64/kernel/pci.c linux/arch/ia64/kernel/pci.c
--- v2.5.2/linux/arch/ia64/kernel/pci.c	Tue Dec 18 14:56:34 2001
+++ linux/arch/ia64/kernel/pci.c	Tue Jan 15 10:56:35 2002
@@ -232,7 +232,7 @@
 	else
 		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
-	if (remap_page_range(vma->vm_start, vma->vm_pgoff << PAGE_SHIFT,
+	if (remap_page_range(vma, vma->vm_start, vma->vm_pgoff << PAGE_SHIFT,
 			     vma->vm_end - vma->vm_start,
 			     vma->vm_page_prot))
 		return -EAGAIN;
diff -u --recursive --new-file v2.5.2/linux/arch/ia64/kernel/perfmon.c linux/arch/ia64/kernel/perfmon.c
--- v2.5.2/linux/arch/ia64/kernel/perfmon.c	Fri Nov  9 14:26:17 2001
+++ linux/arch/ia64/kernel/perfmon.c	Tue Jan 15 10:56:35 2002
@@ -430,14 +430,14 @@
 }
 
 static int
-pfm_remap_buffer(unsigned long buf, unsigned long addr, unsigned long size)
+pfm_remap_buffer(struct vm_area_struct *vma, unsigned long buf, unsigned long addr, unsigned long size)
 {
 	unsigned long page;
 
 	while (size > 0) {
 		page = kvirt_to_pa(buf);
 
-		if (remap_page_range(addr, page, PAGE_SIZE, PAGE_SHARED)) return -ENOMEM;
+		if (remap_page_range(vma, addr, page, PAGE_SIZE, PAGE_SHARED)) return -ENOMEM;
 
 		addr  += PAGE_SIZE;
 		buf   += PAGE_SIZE;
@@ -502,13 +502,26 @@
 	vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
 	if (!vma) goto no_vma;
 
+	/*
+	 * initialize the vma for the sampling buffer
+	 */
+	vma->vm_mm	  = mm;
+	vma->vm_start	  = addr;
+	vma->vm_end	  = addr + size;
+	vma->vm_flags	  = VM_READ|VM_MAYREAD;
+	vma->vm_page_prot = PAGE_READONLY; /* XXX may need to change */
+	vma->vm_ops	  = NULL;
+	vma->vm_pgoff	  = 0;
+	vma->vm_file	  = NULL;
+	vma->vm_raend	  = 0;
+
 	/* XXX: see rvmalloc() for page alignment problem */
 	smpl_buf = rvmalloc(size);
 	if (smpl_buf == NULL) goto no_buffer;
 
 	DBprintk((" smpl_buf @%p\n", smpl_buf));
 
-	if (pfm_remap_buffer((unsigned long)smpl_buf, addr, size)) goto cant_remap;
+	if (pfm_remap_buffer(vma, (unsigned long)smpl_buf, addr, size)) goto cant_remap;
 
 	/* allocate sampling buffer descriptor now */
 	psb = vmalloc(sizeof(*psb));
@@ -539,19 +552,6 @@
 
 	/* link to perfmon context */
 	ctx->ctx_smpl_buf  = psb;
-
-	/*
-	 * initialize the vma for the sampling buffer
-	 */
-	vma->vm_mm	  = mm;
-	vma->vm_start	  = addr;
-	vma->vm_end	  = addr + size;
-	vma->vm_flags	  = VM_READ|VM_MAYREAD;
-	vma->vm_page_prot = PAGE_READONLY; /* XXX may need to change */
-	vma->vm_ops	  = NULL;
-	vma->vm_pgoff	  = 0;
-	vma->vm_file	  = NULL;
-	vma->vm_raend	  = 0;
 
 	vma->vm_private_data = ctx;	/* link to pfm_context(not yet used) */
 
diff -u --recursive --new-file v2.5.2/linux/arch/ia64/kernel/process.c linux/arch/ia64/kernel/process.c
--- v2.5.2/linux/arch/ia64/kernel/process.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/ia64/kernel/process.c	Tue Jan 15 13:53:50 2002
@@ -117,10 +117,10 @@
 
 	while (1) {
 #ifdef CONFIG_SMP
-		if (!current->need_resched)
+		if (!need_resched())
 			min_xtp();
 #endif
-		while (!current->need_resched)
+		while (!need_resched())
 			continue;
 #ifdef CONFIG_SMP
 		normal_xtp();
diff -u --recursive --new-file v2.5.2/linux/arch/ia64/mm/tlb.c linux/arch/ia64/mm/tlb.c
--- v2.5.2/linux/arch/ia64/mm/tlb.c	Fri Nov  9 14:26:17 2001
+++ linux/arch/ia64/mm/tlb.c	Tue Jan 15 10:56:35 2002
@@ -125,8 +125,9 @@
 }
 
 void
-flush_tlb_range (struct mm_struct *mm, unsigned long start, unsigned long end)
+flush_tlb_range (struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long size = end - start;
 	unsigned long nbits;
 
diff -u --recursive --new-file v2.5.2/linux/arch/m68k/kernel/process.c linux/arch/m68k/kernel/process.c
--- v2.5.2/linux/arch/m68k/kernel/process.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/m68k/kernel/process.c	Tue Jan 15 13:53:50 2002
@@ -56,7 +56,7 @@
 static void default_idle(void)
 {
 	while(1) {
-		if (!current->need_resched)
+		if (!need_resched())
 #if defined(MACH_ATARI_ONLY) && !defined(CONFIG_HADES)
 			/* block out HSYNC on the atari (falcon) */
 			__asm__("stop #0x2200" : : : "cc");
diff -u --recursive --new-file v2.5.2/linux/arch/mips/kernel/init_task.c linux/arch/mips/kernel/init_task.c
--- v2.5.2/linux/arch/mips/kernel/init_task.c	Mon Sep 17 15:29:09 2001
+++ linux/arch/mips/kernel/init_task.c	Tue Jan 15 11:06:55 2002
@@ -1,5 +1,6 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
+#include <linux/init_task.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v2.5.2/linux/arch/mips/kernel/process.c linux/arch/mips/kernel/process.c
--- v2.5.2/linux/arch/mips/kernel/process.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/mips/kernel/process.c	Tue Jan 15 13:53:50 2002
@@ -39,7 +39,7 @@
 	init_idle();
 
 	while (1) {
-		while (!current->need_resched)
+		while (!need_resched())
 			if (cpu_wait)
 				(*cpu_wait)();
 		schedule();
diff -u --recursive --new-file v2.5.2/linux/arch/mips/math-emu/cp1emu.c linux/arch/mips/math-emu/cp1emu.c
--- v2.5.2/linux/arch/mips/math-emu/cp1emu.c	Sun Sep  9 10:43:01 2001
+++ linux/arch/mips/math-emu/cp1emu.c	Tue Jan 15 13:53:50 2002
@@ -1674,8 +1674,7 @@
 
 	oldepc = xcp->cp0_epc;
 	do {
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 
 		prevepc = xcp->cp0_epc;
 		insn = mips_get_word(xcp, REG_TO_VA(xcp->cp0_epc), &err);
diff -u --recursive --new-file v2.5.2/linux/arch/mips/mm/andes.c linux/arch/mips/mm/andes.c
--- v2.5.2/linux/arch/mips/mm/andes.c	Sun Sep  9 10:43:02 2001
+++ linux/arch/mips/mm/andes.c	Tue Jan 15 10:56:35 2002
@@ -101,7 +101,7 @@
 	/* XXX */
 }
 
-static void andes_flush_cache_range(struct mm_struct *mm,
+static void andes_flush_cache_range(struct vm_area_struct *vma,
 				    unsigned long start,
 				    unsigned long end)
 {
@@ -147,7 +147,7 @@
 	/* XXX */
 }
 
-void flush_tlb_range(struct mm_struct *mm, unsigned long start,
+void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 				  unsigned long end)
 {
 	/* XXX */
diff -u --recursive --new-file v2.5.2/linux/arch/mips/mm/loadmmu.c linux/arch/mips/mm/loadmmu.c
--- v2.5.2/linux/arch/mips/mm/loadmmu.c	Sun Sep  9 10:43:02 2001
+++ linux/arch/mips/mm/loadmmu.c	Tue Jan 15 10:56:35 2002
@@ -25,7 +25,7 @@
 void (*_flush_cache_all)(void);
 void (*___flush_cache_all)(void);
 void (*_flush_cache_mm)(struct mm_struct *mm);
-void (*_flush_cache_range)(struct mm_struct *mm, unsigned long start,
+void (*_flush_cache_range)(struct vm_area_struct *vma, unsigned long start,
 			  unsigned long end);
 void (*_flush_cache_page)(struct vm_area_struct *vma, unsigned long page);
 void (*_flush_cache_sigtramp)(unsigned long addr);
diff -u --recursive --new-file v2.5.2/linux/arch/mips/mm/mips32.c linux/arch/mips/mm/mips32.c
--- v2.5.2/linux/arch/mips/mm/mips32.c	Sun Sep 30 12:26:08 2001
+++ linux/arch/mips/mm/mips32.c	Tue Jan 15 10:56:35 2002
@@ -176,11 +176,11 @@
 }
 
 static void
-mips32_flush_cache_range_sc(struct mm_struct *mm,
+mips32_flush_cache_range_sc(struct vm_area_struct *vma,
 			 unsigned long start,
 			 unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long flags;
 
 	if(mm->context == 0)
@@ -190,8 +190,7 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
-	if(vma) {
+	if (vma) {
 		if(mm->context != current->mm->context) {
 			mips32_flush_cache_all_sc();
 		} else {
@@ -214,10 +213,12 @@
 	}
 }
 
-static void mips32_flush_cache_range_pc(struct mm_struct *mm,
+static void mips32_flush_cache_range_pc(struct vm_area_struct *vma,
 				     unsigned long start,
 				     unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
+
 	if(mm->context != 0) {
 		unsigned long flags;
 
diff -u --recursive --new-file v2.5.2/linux/arch/mips/mm/r2300.c linux/arch/mips/mm/r2300.c
--- v2.5.2/linux/arch/mips/mm/r2300.c	Sun Sep 30 12:26:08 2001
+++ linux/arch/mips/mm/r2300.c	Tue Jan 15 10:56:35 2002
@@ -336,10 +336,10 @@
 	}
 }
 
-static void r3k_flush_cache_range(struct mm_struct *mm, unsigned long start,
+static void r3k_flush_cache_range(struct vm_area_struct *vma, unsigned long start,
 				  unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 
 	if (mm->context == 0) 
 		return;
@@ -348,10 +348,6 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
-	if (!vma)
-		return;
-
 	if (mm->context != current->active_mm->context) {
 		flush_cache_all();
 	} else {
@@ -485,9 +481,11 @@
 	}
 }
 
-void flush_tlb_range(struct mm_struct *mm, unsigned long start,
+void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
                      unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
+
 	if (mm->context != 0) {
 		unsigned long flags;
 		int size;
diff -u --recursive --new-file v2.5.2/linux/arch/mips/mm/r4xx0.c linux/arch/mips/mm/r4xx0.c
--- v2.5.2/linux/arch/mips/mm/r4xx0.c	Sun Sep 30 12:26:08 2001
+++ linux/arch/mips/mm/r4xx0.c	Tue Jan 15 10:56:35 2002
@@ -989,11 +989,11 @@
 }
 
 static void
-r4k_flush_cache_range_s16d16i16(struct mm_struct *mm,
+r4k_flush_cache_range_s16d16i16(struct vm_area_struct *vma,
                                 unsigned long start,
                                 unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long flags;
 
 	if (mm->context == 0)
@@ -1003,7 +1003,6 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
 	if (vma) {
 		if (mm->context != current->active_mm->context) {
 			r4k_flush_cache_all_s16d16i16();
@@ -1028,11 +1027,11 @@
 }
 
 static void
-r4k_flush_cache_range_s32d16i16(struct mm_struct *mm,
+r4k_flush_cache_range_s32d16i16(struct vm_area_struct *vma,
                                 unsigned long start,
                                 unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long flags;
 
 	if (mm->context == 0)
@@ -1042,7 +1041,6 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
 	if (vma) {
 		if (mm->context != current->active_mm->context) {
 			r4k_flush_cache_all_s32d16i16();
@@ -1066,11 +1064,11 @@
 	}
 }
 
-static void r4k_flush_cache_range_s64d16i16(struct mm_struct *mm,
+static void r4k_flush_cache_range_s64d16i16(struct vm_area_struct *vma,
 					    unsigned long start,
 					    unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long flags;
 
 	if (mm->context == 0)
@@ -1080,7 +1078,6 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
 	if(vma) {
 		if (mm->context != current->active_mm->context) {
 			r4k_flush_cache_all_s64d16i16();
@@ -1104,11 +1101,11 @@
 	}
 }
 
-static void r4k_flush_cache_range_s128d16i16(struct mm_struct *mm,
+static void r4k_flush_cache_range_s128d16i16(struct vm_area_struct *vma,
 					     unsigned long start,
 					     unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long flags;
 
 	if (mm->context == 0)
@@ -1118,7 +1115,6 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
 	if (vma) {
 		if (mm->context != current->active_mm->context) {
 			r4k_flush_cache_all_s128d16i16();
@@ -1142,11 +1138,11 @@
 	}
 }
 
-static void r4k_flush_cache_range_s32d32i32(struct mm_struct *mm,
+static void r4k_flush_cache_range_s32d32i32(struct vm_area_struct *vma,
 					    unsigned long start,
 					    unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long flags;
 
 	if (mm->context == 0)
@@ -1156,7 +1152,6 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
 	if (vma) {
 		if (mm->context != current->active_mm->context) {
 			r4k_flush_cache_all_s32d32i32();
@@ -1180,11 +1175,11 @@
 	}
 }
 
-static void r4k_flush_cache_range_s64d32i32(struct mm_struct *mm,
+static void r4k_flush_cache_range_s64d32i32(struct vm_area_struct *vma,
 					    unsigned long start,
 					    unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long flags;
 
 	if (mm->context == 0)
@@ -1194,7 +1189,6 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
 	if (vma) {
 		if (mm->context != current->active_mm->context) {
 			r4k_flush_cache_all_s64d32i32();
@@ -1218,11 +1212,11 @@
 	}
 }
 
-static void r4k_flush_cache_range_s128d32i32(struct mm_struct *mm,
+static void r4k_flush_cache_range_s128d32i32(struct vm_area_struct *vma,
 					     unsigned long start,
 					     unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long flags;
 
 	if (mm->context == 0)
@@ -1232,7 +1226,6 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
 	if (vma) {
 		if (mm->context != current->active_mm->context) {
 			r4k_flush_cache_all_s128d32i32();
@@ -1256,10 +1249,12 @@
 	}
 }
 
-static void r4k_flush_cache_range_d16i16(struct mm_struct *mm,
+static void r4k_flush_cache_range_d16i16(struct mm_struct *vma,
 					 unsigned long start,
 					 unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
+
 	if (mm->context != 0) {
 		unsigned long flags;
 
@@ -1272,10 +1267,12 @@
 	}
 }
 
-static void r4k_flush_cache_range_d32i32(struct mm_struct *mm,
+static void r4k_flush_cache_range_d32i32(struct vm_area_struct *vma,
 					 unsigned long start,
 					 unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
+
 	if (mm->context != 0) {
 		unsigned long flags;
 
@@ -2160,10 +2157,12 @@
 	}
 }
 
-void flush_tlb_range(struct mm_struct *mm, unsigned long start,
+void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 				unsigned long end)
 {
-	if(mm->context != 0) {
+	struct mm_struct *mm = vma->vm_mm;
+
+	if (mm->context != 0) {
 		unsigned long flags;
 		int size;
 
diff -u --recursive --new-file v2.5.2/linux/arch/mips/mm/r5432.c linux/arch/mips/mm/r5432.c
--- v2.5.2/linux/arch/mips/mm/r5432.c	Sun Sep 30 12:26:08 2001
+++ linux/arch/mips/mm/r5432.c	Tue Jan 15 10:56:35 2002
@@ -366,10 +366,12 @@
 	blast_dcache32(); blast_icache32();
 }
 
-static void r5432_flush_cache_range_d32i32(struct mm_struct *mm,
+static void r5432_flush_cache_range_d32i32(struct vm_area_struct *vma,
 					 unsigned long start,
 					 unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
+
 	if (mm->context != 0) {
 #ifdef DEBUG_CACHE
 		printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
diff -u --recursive --new-file v2.5.2/linux/arch/mips/mm/rm7k.c linux/arch/mips/mm/rm7k.c
--- v2.5.2/linux/arch/mips/mm/rm7k.c	Sun Sep 30 12:26:08 2001
+++ linux/arch/mips/mm/rm7k.c	Tue Jan 15 10:56:35 2002
@@ -171,7 +171,7 @@
 	/* Yes! Caches that don't suck ...  */
 }
 
-static void rm7k_flush_cache_range_d32i32(struct mm_struct *mm,
+static void rm7k_flush_cache_range_d32i32(struct vm_area_struct *vma,
 					 unsigned long start,
 					 unsigned long end)
 {
diff -u --recursive --new-file v2.5.2/linux/arch/mips/mm/sb1.c linux/arch/mips/mm/sb1.c
--- v2.5.2/linux/arch/mips/mm/sb1.c	Wed Jul  4 11:50:39 2001
+++ linux/arch/mips/mm/sb1.c	Tue Jan 15 10:56:35 2002
@@ -264,7 +264,7 @@
 	/* Don't need to do this, as the dcache is physically tagged */
 }
 
-static void sb1_flush_cache_range(struct mm_struct *mm, 
+static void sb1_flush_cache_range(struct vm_area_struct *vma,
 				  unsigned long start,
 				  unsigned long end)
 {
diff -u --recursive --new-file v2.5.2/linux/arch/mips/mm/umap.c linux/arch/mips/mm/umap.c
--- v2.5.2/linux/arch/mips/mm/umap.c	Wed Jul  4 11:50:39 2001
+++ linux/arch/mips/mm/umap.c	Tue Jan 15 10:56:35 2002
@@ -88,20 +88,20 @@
  * range of active mappings at this point
  */
 void
-remove_mapping (struct task_struct *task, unsigned long start, unsigned long end)
+remove_mapping (struct vm_area_struct *vma, struct task_struct *task, unsigned long start, unsigned long end)
 {
 	unsigned long beg = start;
 	pgd_t *dir;
 
 	down_write (&task->mm->mmap_sem);
 	dir = pgd_offset (task->mm, start);
-	flush_cache_range (task->mm, beg, end);
+	flush_cache_range (vma, beg, end);
 	while (start < end){
 		remove_mapping_pmd_range (dir, start, end - start);
 		start = (start + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	}
-	flush_tlb_range (task->mm, beg, end);
+	flush_tlb_range (vma, beg, end);
 	up_write (&task->mm->mmap_sem);
 }
 
@@ -192,7 +192,7 @@
 }
 
 int
-vmap_page_range (unsigned long from, unsigned long size, unsigned long vaddr)
+vmap_page_range (struct vm_area_struct *vma, unsigned long from, unsigned long size, unsigned long vaddr)
 {
 	int error = 0;
 	pgd_t * dir;
@@ -201,7 +201,7 @@
 
 	vaddr -= from;
 	dir = pgd_offset(current->mm, from);
-	flush_cache_range(current->mm, beg, end);
+	flush_cache_range(vma, beg, end);
 	while (from < end) {
 		pmd_t *pmd = pmd_alloc(current->mm, dir, from);
 		error = -ENOMEM;
@@ -213,6 +213,6 @@
 		from = (from + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	}
-	flush_tlb_range(current->mm, beg, end);
+	flush_tlb_range(vma, beg, end);
 	return error;
 }
diff -u --recursive --new-file v2.5.2/linux/arch/mips64/kernel/init_task.c linux/arch/mips64/kernel/init_task.c
--- v2.5.2/linux/arch/mips64/kernel/init_task.c	Mon Sep 17 15:29:09 2001
+++ linux/arch/mips64/kernel/init_task.c	Tue Jan 15 11:06:55 2002
@@ -1,5 +1,6 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
+#include <linux/init_task.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v2.5.2/linux/arch/mips64/kernel/process.c linux/arch/mips64/kernel/process.c
--- v2.5.2/linux/arch/mips64/kernel/process.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/mips64/kernel/process.c	Tue Jan 15 13:53:50 2002
@@ -35,7 +35,7 @@
 	init_idle();
 	current->nice = 20;
 	while (1) {
-		while (!current->need_resched)
+		while (!need_resched())
 			if (wait_available)
 				__asm__("wait");
 		schedule();
diff -u --recursive --new-file v2.5.2/linux/arch/mips64/kernel/smp.c linux/arch/mips64/kernel/smp.c
--- v2.5.2/linux/arch/mips64/kernel/smp.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/mips64/kernel/smp.c	Tue Jan 15 10:56:35 2002
@@ -242,15 +242,15 @@
 {
 	struct flush_tlb_data *fd = (struct flush_tlb_data *)info;
 
-	_flush_tlb_range(fd->mm, fd->addr1, fd->addr2);
+	_flush_tlb_range(fd->vma, fd->addr1, fd->addr2);
 }
 
-void flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
 	if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) {
 		struct flush_tlb_data fd;
 
-		fd.mm = mm;
+		fd.vma = vma;
 		fd.addr1 = start;
 		fd.addr2 = end;
 		smp_call_function(flush_tlb_range_ipi, (void *)&fd, 1, 1);
diff -u --recursive --new-file v2.5.2/linux/arch/mips64/math-emu/cp1emu.c linux/arch/mips64/math-emu/cp1emu.c
--- v2.5.2/linux/arch/mips64/math-emu/cp1emu.c	Sun Sep  9 10:43:02 2001
+++ linux/arch/mips64/math-emu/cp1emu.c	Tue Jan 15 13:53:50 2002
@@ -1707,8 +1707,7 @@
 
 	oldepc = xcp->cp0_epc;
 	do {
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 
 		prevepc = xcp->cp0_epc;
 		insn = mips_get_word(xcp, REG_TO_VA(xcp->cp0_epc), &err);
diff -u --recursive --new-file v2.5.2/linux/arch/mips64/mm/andes.c linux/arch/mips64/mm/andes.c
--- v2.5.2/linux/arch/mips64/mm/andes.c	Sun Sep 30 12:26:08 2001
+++ linux/arch/mips64/mm/andes.c	Tue Jan 15 10:56:35 2002
@@ -179,9 +179,11 @@
 }
 
 static void
-andes_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+andes_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
                       unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
+
 	if (CPU_CONTEXT(smp_processor_id(), mm) != 0) {
 		unsigned long flags;
 		int size;
diff -u --recursive --new-file v2.5.2/linux/arch/mips64/mm/loadmmu.c linux/arch/mips64/mm/loadmmu.c
--- v2.5.2/linux/arch/mips64/mm/loadmmu.c	Sun Sep  9 10:43:02 2001
+++ linux/arch/mips64/mm/loadmmu.c	Tue Jan 15 10:56:35 2002
@@ -25,7 +25,7 @@
 
 /* Cache operations. */
 void (*_flush_cache_mm)(struct mm_struct *mm);
-void (*_flush_cache_range)(struct mm_struct *mm, unsigned long start,
+void (*_flush_cache_range)(struct vm_area_struct *vma, unsigned long start,
                            unsigned long end);
 void (*_flush_cache_page)(struct vm_area_struct *vma, unsigned long page);
 void (*_flush_page_to_ram)(struct page * page);
@@ -44,7 +44,7 @@
 /* TLB operations. */
 void (*_flush_tlb_all)(void);
 void (*_flush_tlb_mm)(struct mm_struct *mm);
-void (*_flush_tlb_range)(struct mm_struct *mm, unsigned long start,
+void (*_flush_tlb_range)(struct vm_area_struct *vma, unsigned long start,
 			unsigned long end);
 void (*_flush_tlb_page)(struct vm_area_struct *vma, unsigned long page);
 
diff -u --recursive --new-file v2.5.2/linux/arch/mips64/mm/r4xx0.c linux/arch/mips64/mm/r4xx0.c
--- v2.5.2/linux/arch/mips64/mm/r4xx0.c	Sun Sep 30 12:26:08 2001
+++ linux/arch/mips64/mm/r4xx0.c	Tue Jan 15 10:56:35 2002
@@ -776,11 +776,11 @@
 	__restore_flags(flags);
 }
 
-static void r4k_flush_cache_range_s16d16i16(struct mm_struct *mm,
+static void r4k_flush_cache_range_s16d16i16(struct vm_area_struct *vma,
 					    unsigned long start,
 					    unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long flags;
 
 	if (CPU_CONTEXT(smp_processor_id(), mm) == 0)
@@ -790,8 +790,7 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
-	if(vma) {
+	if (vma) {
 		if (CPU_CONTEXT(smp_processor_id(), mm) !=
 				CPU_CONTEXT(smp_processor_id(), current->mm)) {
 			r4k_flush_cache_all_s16d16i16();
@@ -815,11 +814,11 @@
 	}
 }
 
-static void r4k_flush_cache_range_s32d16i16(struct mm_struct *mm,
+static void r4k_flush_cache_range_s32d16i16(struct vm_area_struct *vma,
 					    unsigned long start,
 					    unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long flags;
 
 	if (CPU_CONTEXT(smp_processor_id(), mm) == 0)
@@ -829,8 +828,7 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
-	if(vma) {
+	if (vma) {
 		if (CPU_CONTEXT(smp_processor_id(), mm) !=
 				CPU_CONTEXT(smp_processor_id(), current->mm)) {
 			r4k_flush_cache_all_s32d16i16();
@@ -854,11 +852,11 @@
 	}
 }
 
-static void r4k_flush_cache_range_s64d16i16(struct mm_struct *mm,
+static void r4k_flush_cache_range_s64d16i16(struct vm_area_struct *vma,
 					    unsigned long start,
 					    unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long flags;
 
 	if (CPU_CONTEXT(smp_processor_id(), mm) == 0)
@@ -868,8 +866,7 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
-	if(vma) {
+	if (vma) {
 		if (CPU_CONTEXT(smp_processor_id(), mm) !=
 				CPU_CONTEXT(smp_processor_id(), current->mm)) {
 			r4k_flush_cache_all_s64d16i16();
@@ -893,11 +890,11 @@
 	}
 }
 
-static void r4k_flush_cache_range_s128d16i16(struct mm_struct *mm,
+static void r4k_flush_cache_range_s128d16i16(struct vm_area_struct *vma,
 					     unsigned long start,
 					     unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long flags;
 
 	if (CPU_CONTEXT(smp_processor_id(), mm) == 0)
@@ -907,8 +904,7 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
-	if(vma) {
+	if (vma) {
 		if (CPU_CONTEXT(smp_processor_id(), mm) !=
 				CPU_CONTEXT(smp_processor_id(), current->mm)) {
 			r4k_flush_cache_all_s128d16i16();
@@ -932,11 +928,11 @@
 	}
 }
 
-static void r4k_flush_cache_range_s32d32i32(struct mm_struct *mm,
+static void r4k_flush_cache_range_s32d32i32(struct vm_area_struct *vma,
 					    unsigned long start,
 					    unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long flags;
 
 	if (CPU_CONTEXT(smp_processor_id(), mm) == 0)
@@ -946,8 +942,7 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
-	if(vma) {
+	if (vma) {
 		if (CPU_CONTEXT(smp_processor_id(), mm) !=
 				CPU_CONTEXT(smp_processor_id(), current->mm)) {
 			r4k_flush_cache_all_s32d32i32();
@@ -971,11 +966,11 @@
 	}
 }
 
-static void r4k_flush_cache_range_s64d32i32(struct mm_struct *mm,
+static void r4k_flush_cache_range_s64d32i32(struct vm_area_struct *vma,
 					    unsigned long start,
 					    unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long flags;
 
 	if (CPU_CONTEXT(smp_processor_id(), mm) == 0)
@@ -985,8 +980,7 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
-	if(vma) {
+	if (vma) {
 		if (CPU_CONTEXT(smp_processor_id(), mm) !=
 				CPU_CONTEXT(smp_processor_id(), current->mm)) {
 			r4k_flush_cache_all_s64d32i32();
@@ -1010,11 +1004,11 @@
 	}
 }
 
-static void r4k_flush_cache_range_s128d32i32(struct mm_struct *mm,
+static void r4k_flush_cache_range_s128d32i32(struct vm_area_struct *vma,
 					     unsigned long start,
 					     unsigned long end)
 {
-	struct vm_area_struct *vma;
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long flags;
 
 	if (CPU_CONTEXT(smp_processor_id(), mm) != 0)
@@ -1024,8 +1018,7 @@
 #ifdef DEBUG_CACHE
 	printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
 #endif
-	vma = find_vma(mm, start);
-	if(vma) {
+	if (vma) {
 		if (CPU_CONTEXT(smp_processor_id(), mm) !=
 				CPU_CONTEXT(smp_processor_id(), current->mm)) {
 			r4k_flush_cache_all_s128d32i32();
@@ -1049,10 +1042,12 @@
 	}
 }
 
-static void r4k_flush_cache_range_d16i16(struct mm_struct *mm,
+static void r4k_flush_cache_range_d16i16(struct vm_area_struct *vma,
 					 unsigned long start,
 					 unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
+
 	if (CPU_CONTEXT(smp_processor_id(), mm) != 0) {
 		unsigned long flags;
 
@@ -1065,10 +1060,12 @@
 	}
 }
 
-static void r4k_flush_cache_range_d32i32(struct mm_struct *mm,
+static void r4k_flush_cache_range_d32i32(struct vm_area_struct *vma,
 					 unsigned long start,
 					 unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
+
 	if (CPU_CONTEXT(smp_processor_id(), mm) != 0) {
 		unsigned long flags;
 
@@ -1913,9 +1910,11 @@
 	}
 }
 
-static void r4k_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+static void r4k_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 				unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
+
 	if (CPU_CONTEXT(smp_processor_id(), mm) != 0) {
 		unsigned long flags;
 		int size;
diff -u --recursive --new-file v2.5.2/linux/arch/mips64/mm/umap.c linux/arch/mips64/mm/umap.c
--- v2.5.2/linux/arch/mips64/mm/umap.c	Sun Sep  9 10:43:02 2001
+++ linux/arch/mips64/mm/umap.c	Tue Jan 15 10:56:35 2002
@@ -86,7 +86,7 @@
  * This routine is called from the page fault handler to remove a
  * range of active mappings at this point
  */
-void remove_mapping (struct task_struct *task, unsigned long start,
+void remove_mapping (struct vm_area_struct *vma, struct task_struct *task, unsigned long start,
 		     unsigned long end)
 {
 	unsigned long beg = start;
@@ -94,13 +94,13 @@
 
 	down_write (&task->mm->mmap_sem);
 	dir = pgd_offset (task->mm, start);
-	flush_cache_range (task->mm, beg, end);
+	flush_cache_range (vma, beg, end);
 	while (start < end){
 		remove_mapping_pmd_range (dir, start, end - start);
 		start = (start + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	}
-	flush_tlb_range (task->mm, beg, end);
+	flush_tlb_range (vma, beg, end);
 	up_write (&task->mm->mmap_sem);
 }
 
@@ -190,7 +190,7 @@
 	return 0;
 }
 
-int vmap_page_range (unsigned long from, unsigned long size,
+int vmap_page_range (struct vm_area_struct *vma, unsigned long from, unsigned long size,
 		     unsigned long vaddr)
 {
 	int error = 0;
@@ -200,7 +200,7 @@
 
 	vaddr -= from;
 	dir = pgd_offset(current->mm, from);
-	flush_cache_range(current->mm, beg, end);
+	flush_cache_range(vma, beg, end);
 	while (from < end) {
 		pmd_t *pmd = pmd_alloc(current->mm, dir, from);
 		error = -ENOMEM;
@@ -212,6 +212,6 @@
 		from = (from + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	}
-	flush_tlb_range(current->mm, beg, end);
+	flush_tlb_range(vma, beg, end);
 	return error;
 }
diff -u --recursive --new-file v2.5.2/linux/arch/parisc/kernel/init_task.c linux/arch/parisc/kernel/init_task.c
--- v2.5.2/linux/arch/parisc/kernel/init_task.c	Mon Sep 17 15:29:09 2001
+++ linux/arch/parisc/kernel/init_task.c	Tue Jan 15 11:06:55 2002
@@ -1,6 +1,7 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/init.h>
+#include <linux/init_task.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v2.5.2/linux/arch/parisc/kernel/process.c linux/arch/parisc/kernel/process.c
--- v2.5.2/linux/arch/parisc/kernel/process.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/parisc/kernel/process.c	Tue Jan 15 13:57:50 2002
@@ -73,8 +73,8 @@
 	current->nice = 20;
 
 	while (1) {
-		while (!current->need_resched) {
-		}
+		while (!need_resched())
+			barrier();
 		schedule();
 		check_pgt_cache();
 	}
diff -u --recursive --new-file v2.5.2/linux/arch/parisc/mm/kmap.c linux/arch/parisc/mm/kmap.c
--- v2.5.2/linux/arch/parisc/mm/kmap.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/parisc/mm/kmap.c	Tue Jan 15 10:56:35 2002
@@ -128,11 +128,11 @@
 	switch (what) {
 	case IOMAP_FULL_CACHING:
 		iterate_pages(vaddr, size, set_cached, 0);
-		flush_tlb_range(&init_mm, vaddr, size);
+		flush_tlb_range(NULL, vaddr, size);
 		break;
 	case IOMAP_NOCACHE_SER:
 		iterate_pages(vaddr, size, set_uncached, 0);
-		flush_tlb_range(&init_mm, vaddr, size);
+		flush_tlb_range(NULL, vaddr, size);
 		break;
 	default:
 		printk(KERN_CRIT
diff -u --recursive --new-file v2.5.2/linux/arch/parisc/mm/pa11.c linux/arch/parisc/mm/pa11.c
--- v2.5.2/linux/arch/parisc/mm/pa11.c	Sun Sep 30 12:26:08 2001
+++ linux/arch/parisc/mm/pa11.c	Tue Jan 15 10:56:35 2002
@@ -28,7 +28,7 @@
 /* Cache operations. */
 static inline void pa11_flush_cache_all(void) { }
 static void pa11_flush_cache_mm(struct mm_struct *mm) { }
-static void pa11_flush_cache_range(struct mm_struct *mm,
+static void pa11_flush_cache_range(struct vm_area_struct *vma,
 				    unsigned long start,
 				    unsigned long end)
 {
@@ -65,10 +65,10 @@
 		pa11_flush_tlb_all();
 }
 
-static void pa11_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+static void pa11_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 				  unsigned long end)
 {
-	if(mm == current->mm)
+	if (vma == NULL || vma->vm_mm == current->mm)
 		pa11_flush_tlb_all();
 }
 
diff -u --recursive --new-file v2.5.2/linux/arch/parisc/mm/pa20.c linux/arch/parisc/mm/pa20.c
--- v2.5.2/linux/arch/parisc/mm/pa20.c	Sun Sep 30 12:26:08 2001
+++ linux/arch/parisc/mm/pa20.c	Tue Jan 15 10:56:35 2002
@@ -28,7 +28,7 @@
 /* Cache operations. */
 static inline void pa20_flush_cache_all(void) { }
 static void pa20_flush_cache_mm(struct mm_struct *mm) { }
-static void pa20_flush_cache_range(struct mm_struct *mm,
+static void pa20_flush_cache_range(struct vm_area_struct *vma,
 				    unsigned long start,
 				    unsigned long end)
 {
@@ -65,10 +65,10 @@
 		pa20_flush_tlb_all();
 }
 
-static void pa20_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+static void pa20_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 				  unsigned long end)
 {
-	if(mm == current->mm)
+	if (vma == NULL || vma->vm_mm == current->mm)
 		pa20_flush_tlb_all();
 }
 
diff -u --recursive --new-file v2.5.2/linux/arch/ppc/kernel/idle.c linux/arch/ppc/kernel/idle.c
--- v2.5.2/linux/arch/ppc/kernel/idle.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/ppc/kernel/idle.c	Tue Jan 15 13:57:16 2002
@@ -66,15 +66,15 @@
 			int oldval = xchg(&current->need_resched, -1);
 
 			if (!oldval) {
-				while(current->need_resched == -1)
-					; /* Do Nothing */
+				while (need_resched())
+					barrier(); /* Do Nothing */
 			}
 		}
 #endif
-		if (do_power_save && !current->need_resched)
+		if (do_power_save && !need_resched())
 			power_save();
 
-		if (current->need_resched) {
+		if (need_resched()) {
 			schedule();
 			check_pgt_cache();
 		}
@@ -150,7 +150,7 @@
 
 	if ( atomic_read(&zero_cache_sz) >= zero_cache_water[0] )
 		return;
-	while ( (atomic_read(&zero_cache_sz) < zero_cache_water[1]) && (!current->need_resched) )
+	while ( (atomic_read(&zero_cache_sz) < zero_cache_water[1]) && !need_resched() )
 	{
 		/*
 		 * Mark a page as reserved so we can mess with it
@@ -161,8 +161,7 @@
 		if ( !pageptr )
 			return;
 		
-		if ( current->need_resched )
-			schedule();
+		cond_resched();
 		
 		/*
 		 * Make the page no cache so we don't blow our cache with 0's
@@ -181,8 +180,7 @@
 		 */
 		for ( bytecount = 0; bytecount < PAGE_SIZE ; bytecount += 4 )
 		{
-			if ( current->need_resched )
-				schedule();
+			cond_resched();
 			*(unsigned long *)(bytecount + pageptr) = 0;
 		}
 		
@@ -243,7 +241,7 @@
 	 *  -- Cort
 	 */
 	_nmask_and_or_msr(MSR_EE, 0);
-	if (!current->need_resched)
+	if (!need_resched())
 	{
 		asm("mfspr %0,1008" : "=r" (hid0) :);
 		hid0 &= ~(HID0_NAP | HID0_SLEEP | HID0_DOZE);
diff -u --recursive --new-file v2.5.2/linux/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c
--- v2.5.2/linux/arch/ppc/kernel/pci.c	Fri Nov 16 10:10:08 2001
+++ linux/arch/ppc/kernel/pci.c	Tue Jan 15 10:56:35 2002
@@ -1068,7 +1068,7 @@
 	__pci_mmap_set_flags(dev, vma, mmap_state);
 	__pci_mmap_set_pgprot(dev, vma, mmap_state, write_combine);
 
-	ret = remap_page_range(vma->vm_start, vma->vm_pgoff << PAGE_SHIFT,
+	ret = remap_page_range(vma, vma->vm_start, vma->vm_pgoff << PAGE_SHIFT,
 			       vma->vm_end - vma->vm_start, vma->vm_page_prot);
 
 	return ret;
diff -u --recursive --new-file v2.5.2/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c
--- v2.5.2/linux/arch/ppc/kernel/setup.c	Wed Nov 21 09:59:11 2001
+++ linux/arch/ppc/kernel/setup.c	Fri Jan 18 16:17:45 2002
@@ -689,8 +689,12 @@
 	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
 	id->word92         = __le16_to_cpu(id->word92);
 	id->hw_config      = __le16_to_cpu(id->hw_config);
-	for (i = 0; i < 32; i++)
-		id->words94_125[i]  = __le16_to_cpu(id->words94_125[i]);
+	id->acoustic       = __le16_to_cpu(id->acoustic);
+	for (i = 0; i < 5; i++)
+		id->words95_99[i]  = __le16_to_cpu(id->words95_99[i]);
+	id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
+	for (i = 0; i < 22; i++)
+		id->words104_125[i]   = __le16_to_cpu(id->words104_125[i]);
 	id->last_lun       = __le16_to_cpu(id->last_lun);
 	id->word127        = __le16_to_cpu(id->word127);
 	id->dlf            = __le16_to_cpu(id->dlf);
@@ -700,6 +704,12 @@
 	id->word156        = __le16_to_cpu(id->word156);
 	for (i = 0; i < 3; i++)
 		id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
-	for (i = 0; i < 96; i++)
-		id->words160_255[i] = __le16_to_cpu(id->words160_255[i]);
+	id->cfa_power      = __le16_to_cpu(id->cfa_power);
+	for (i = 0; i < 14; i++)
+		id->words161_175[i] = __le16_to_cpu(id->words161_175[i]);
+	for (i = 0; i < 31; i++)
+		id->words176_205[i] = __le16_to_cpu(id->words176_205[i]);
+	for (i = 0; i < 48; i++)
+		id->words206_254[i] = __le16_to_cpu(id->words206_254[i]);
+	id->integrity_word  = __le16_to_cpu(id->integrity_word);
 }
diff -u --recursive --new-file v2.5.2/linux/arch/ppc/mm/tlb.c linux/arch/ppc/mm/tlb.c
--- v2.5.2/linux/arch/ppc/mm/tlb.c	Tue Aug 28 06:58:33 2001
+++ linux/arch/ppc/mm/tlb.c	Tue Jan 15 10:56:35 2002
@@ -39,7 +39,7 @@
  *  - flush_tlb_all() flushes all processes TLBs
  *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
  *  - flush_tlb_page(vma, vmaddr) flushes one page
- *  - flush_tlb_range(mm, start, end) flushes a range of pages
+ *  - flush_tlb_range(vma, start, end) flushes a range of pages
  *
  * since the hardware hash table functions as an extension of the
  * tlb as far as the linux tables are concerned, flush it too.
@@ -53,6 +53,8 @@
 void
 local_flush_tlb_all(void)
 {
+	struct vm_area_struct vma;
+
 	/* aargh!!! */
 	/*
 	 * Just flush the kernel part of the address space, that's
@@ -61,7 +63,8 @@
 	 * we can and should dispense with flush_tlb_all().
 	 *  -- paulus.
 	 */
-	local_flush_tlb_range(&init_mm, TASK_SIZE, ~0UL);
+	vma.vm_mm = &init_mm;
+	local_flush_tlb_range(&vma, TASK_SIZE, ~0UL);
 
 #ifdef CONFIG_SMP
 	smp_send_tlb_invalidate(0);
@@ -84,9 +87,12 @@
 	if (mm->map_count) {
 		struct vm_area_struct *mp;
 		for (mp = mm->mmap; mp != NULL; mp = mp->vm_next)
-			local_flush_tlb_range(mm, mp->vm_start, mp->vm_end);
-	} else
-		local_flush_tlb_range(mm, 0, TASK_SIZE);
+			local_flush_tlb_range(mp, mp->vm_start, mp->vm_end);
+	} else {
+		struct vm_area_struct vma;
+		vma.vm_mm = mm;
+		local_flush_tlb_range(&vma, 0, TASK_SIZE);
+	}
 
 #ifdef CONFIG_SMP
 	smp_send_tlb_invalidate(0);
@@ -123,8 +129,9 @@
  * the corresponding HPTE.
  */
 void
-local_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
 	pmd_t *pmd;
 	pte_t *pte;
 	unsigned long pmd_end;
diff -u --recursive --new-file v2.5.2/linux/arch/s390/kernel/init_task.c linux/arch/s390/kernel/init_task.c
--- v2.5.2/linux/arch/s390/kernel/init_task.c	Fri Nov  9 13:58:02 2001
+++ linux/arch/s390/kernel/init_task.c	Tue Jan 15 11:06:55 2002
@@ -8,6 +8,7 @@
 
 #include <linux/mm.h>
 #include <linux/sched.h>
+#include <linux/init_task.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v2.5.2/linux/arch/s390/kernel/process.c linux/arch/s390/kernel/process.c
--- v2.5.2/linux/arch/s390/kernel/process.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/s390/kernel/process.c	Tue Jan 15 13:53:50 2002
@@ -60,7 +60,7 @@
 	wait_psw.mask = _WAIT_PSW_MASK;
 	wait_psw.addr = (unsigned long) &&idle_wakeup | 0x80000000L;
 	while(1) {
-                if (current->need_resched) {
+                if (need_resched()) {
                         schedule();
                         check_pgt_cache();
                         continue;
diff -u --recursive --new-file v2.5.2/linux/arch/s390x/kernel/init_task.c linux/arch/s390x/kernel/init_task.c
--- v2.5.2/linux/arch/s390x/kernel/init_task.c	Fri Nov  9 13:58:02 2001
+++ linux/arch/s390x/kernel/init_task.c	Tue Jan 15 11:06:55 2002
@@ -8,6 +8,7 @@
 
 #include <linux/mm.h>
 #include <linux/sched.h>
+#include <linux/init_task.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v2.5.2/linux/arch/s390x/kernel/process.c linux/arch/s390x/kernel/process.c
--- v2.5.2/linux/arch/s390x/kernel/process.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/s390x/kernel/process.c	Tue Jan 15 13:53:50 2002
@@ -60,7 +60,7 @@
 	wait_psw.mask = _WAIT_PSW_MASK;
 	wait_psw.addr = (unsigned long) &&idle_wakeup;
 	while(1) {
-                if (current->need_resched) {
+                if (need_resched()) {
                         schedule();
                         check_pgt_cache();
                         continue;
diff -u --recursive --new-file v2.5.2/linux/arch/sh/kernel/init_task.c linux/arch/sh/kernel/init_task.c
--- v2.5.2/linux/arch/sh/kernel/init_task.c	Mon Sep 17 15:29:09 2001
+++ linux/arch/sh/kernel/init_task.c	Tue Jan 15 11:06:55 2002
@@ -1,6 +1,7 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/init.h>
+#include <linux/init_task.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v2.5.2/linux/arch/sh/kernel/process.c linux/arch/sh/kernel/process.c
--- v2.5.2/linux/arch/sh/kernel/process.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/sh/kernel/process.c	Tue Jan 15 13:53:50 2002
@@ -44,11 +44,11 @@
 
 	while (1) {
 		if (hlt_counter) {
-			if (current->need_resched)
+			if (need_resched())
 				break;
 		} else {
 			__cli();
-			while (!current->need_resched) {
+			while (!need_resched()) {
 				__sti();
 				asm volatile("sleep" : : : "memory");
 				__cli();
diff -u --recursive --new-file v2.5.2/linux/arch/sh/mm/cache-sh4.c linux/arch/sh/mm/cache-sh4.c
--- v2.5.2/linux/arch/sh/mm/cache-sh4.c	Mon Oct 15 13:36:48 2001
+++ linux/arch/sh/mm/cache-sh4.c	Tue Jan 15 10:56:35 2002
@@ -295,7 +295,7 @@
  * Flushing the cache lines for U0 only isn't enough.
  * We need to flush for P1 too, which may contain aliases.
  */
-void flush_cache_range(struct mm_struct *mm, unsigned long start,
+void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
 		       unsigned long end)
 {
 	/*
diff -u --recursive --new-file v2.5.2/linux/arch/sh/mm/fault.c linux/arch/sh/mm/fault.c
--- v2.5.2/linux/arch/sh/mm/fault.c	Mon Oct 15 13:36:48 2001
+++ linux/arch/sh/mm/fault.c	Tue Jan 15 10:56:35 2002
@@ -374,9 +374,11 @@
 	}
 }
 
-void flush_tlb_range(struct mm_struct *mm, unsigned long start,
+void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 		     unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
+
 	if (mm->context != NO_CONTEXT) {
 		unsigned long flags;
 		int size;
diff -u --recursive --new-file v2.5.2/linux/arch/sparc/config.in linux/arch/sparc/config.in
--- v2.5.2/linux/arch/sparc/config.in	Mon Jan 14 18:25:08 2002
+++ linux/arch/sparc/config.in	Tue Jan 15 10:52:11 2002
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.111 2001/06/01 08:12:10 davem Exp $
+# $Id: config.in,v 1.112 2002/01/15 06:25:50 davem Exp $
 # For a description of the syntax of this configuration file,
 # see Documentation/kbuild/config-language.txt.
 #
diff -u --recursive --new-file v2.5.2/linux/arch/sparc/defconfig linux/arch/sparc/defconfig
--- v2.5.2/linux/arch/sparc/defconfig	Tue Nov 13 09:16:05 2001
+++ linux/arch/sparc/defconfig	Tue Jan 15 10:52:11 2002
@@ -138,7 +138,7 @@
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK is not set
+CONFIG_NETLINK_DEV=y
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
 CONFIG_UNIX=y
@@ -148,6 +148,7 @@
 # CONFIG_IP_PNP is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
 CONFIG_IPV6=m
@@ -288,7 +289,7 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_TMPFS is not set
-# CONFIG_RAMFS is not set
+CONFIG_RAMFS=y
 CONFIG_ISO9660_FS=m
 # CONFIG_JOLIET is not set
 # CONFIG_ZISOFS is not set
@@ -402,3 +403,8 @@
 # Kernel hacking
 #
 # CONFIG_MAGIC_SYSRQ is not set
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
diff -u --recursive --new-file v2.5.2/linux/arch/sparc/kernel/init_task.c linux/arch/sparc/kernel/init_task.c
--- v2.5.2/linux/arch/sparc/kernel/init_task.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/sparc/kernel/init_task.c	Tue Jan 15 11:06:55 2002
@@ -1,5 +1,6 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
+#include <linux/init_task.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
diff -u --recursive --new-file v2.5.2/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c
--- v2.5.2/linux/arch/sparc/kernel/process.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/sparc/kernel/process.c	Tue Jan 15 13:53:50 2002
@@ -106,7 +106,7 @@
 {
 	/* endless idle loop with no priority at all */
 	while(1) {
-		if(current->need_resched) {
+		if(need_resched()) {
 			schedule();
 			check_pgt_cache();
 		}
diff -u --recursive --new-file v2.5.2/linux/arch/sparc/kernel/smp.c linux/arch/sparc/kernel/smp.c
--- v2.5.2/linux/arch/sparc/kernel/smp.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/sparc/kernel/smp.c	Tue Jan 15 10:56:35 2002
@@ -177,23 +177,27 @@
 	}
 }
 
-void smp_flush_cache_range(struct mm_struct *mm, unsigned long start,
+void smp_flush_cache_range(struct vm_area_struct *vma, unsigned long start,
 			   unsigned long end)
 {
-	if(mm->context != NO_CONTEXT) {
+	struct mm_struct *mm = vma->vm_mm;
+
+	if (mm->context != NO_CONTEXT) {
 		if(mm->cpu_vm_mask != (1 << smp_processor_id()))
-			xc3((smpfunc_t) BTFIXUP_CALL(local_flush_cache_range), (unsigned long) mm, start, end);
-		local_flush_cache_range(mm, start, end);
+			xc3((smpfunc_t) BTFIXUP_CALL(local_flush_cache_range), (unsigned long) vma, start, end);
+		local_flush_cache_range(vma, start, end);
 	}
 }
 
-void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+void smp_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 			 unsigned long end)
 {
-	if(mm->context != NO_CONTEXT) {
+	struct mm_struct *mm = vma->vm_mm;
+
+	if (mm->context != NO_CONTEXT) {
 		if(mm->cpu_vm_mask != (1 << smp_processor_id()))
-			xc3((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_range), (unsigned long) mm, start, end);
-		local_flush_tlb_range(mm, start, end);
+			xc3((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_range), (unsigned long) vma, start, end);
+		local_flush_tlb_range(vma, start, end);
 	}
 }
 
diff -u --recursive --new-file v2.5.2/linux/arch/sparc/mm/generic.c linux/arch/sparc/mm/generic.c
--- v2.5.2/linux/arch/sparc/mm/generic.c	Thu Jul 19 18:11:13 2001
+++ linux/arch/sparc/mm/generic.c	Tue Jan 15 10:56:35 2002
@@ -1,4 +1,4 @@
-/* $Id: generic.c,v 1.13 2001/07/17 16:17:33 anton Exp $
+/* $Id: generic.c,v 1.14 2001/12/21 04:56:15 davem Exp $
  * generic.c: Generic Sparc mm routines that are not dependent upon
  *            MMU type but are Sparc specific.
  *
@@ -75,18 +75,18 @@
 	return 0;
 }
 
-int io_remap_page_range(unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space)
+int io_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space)
 {
 	int error = 0;
 	pgd_t * dir;
 	unsigned long beg = from;
 	unsigned long end = from + size;
-	struct mm_struct *mm = current->mm;
+	struct mm_struct *mm = vma->vm_mm;
 
 	prot = __pgprot(pg_iobits);
 	offset -= from;
 	dir = pgd_offset(mm, from);
-	flush_cache_range(mm, beg, end);
+	flush_cache_range(vma, beg, end);
 
 	spin_lock(&mm->page_table_lock);
 	while (from < end) {
@@ -102,6 +102,6 @@
 	}
 	spin_unlock(&mm->page_table_lock);
 
-	flush_tlb_range(current->mm, beg, end);
+	flush_tlb_range(vma, beg, end);
 	return error;
 }
diff -u --recursive --new-file v2.5.2/linux/arch/sparc/mm/hypersparc.S linux/arch/sparc/mm/hypersparc.S
--- v2.5.2/linux/arch/sparc/mm/hypersparc.S	Tue Jul 18 12:29:47 2000
+++ linux/arch/sparc/mm/hypersparc.S	Tue Jan 15 10:56:35 2002
@@ -1,4 +1,4 @@
-/* $Id: hypersparc.S,v 1.17 2000/07/16 21:48:52 anton Exp $
+/* $Id: hypersparc.S,v 1.18 2001/12/21 04:56:15 davem Exp $
  * hypersparc.S: High speed Hypersparc mmu/cache operations.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -74,6 +74,7 @@
 
 	/* The things we do for performance... */
 hypersparc_flush_cache_range:
+	ld	[%o0 + 0x0], %o0		/* XXX vma->vm_mm, GROSS XXX */
 #ifndef CONFIG_SMP
 	ld	[%o0 + AOFF_mm_context], %g1
 	cmp	%g1, -1
@@ -283,6 +284,7 @@
 	 sta	%g5, [%g1] ASI_M_MMUREGS
 
 hypersparc_flush_tlb_range:
+	ld	[%o0 + 0x00], %o0	/* XXX vma->vm_mm GROSS XXX */
 	mov	SRMMU_CTX_REG, %g1
 	ld	[%o0 + AOFF_mm_context], %o3
 	lda	[%g1] ASI_M_MMUREGS, %g5
diff -u --recursive --new-file v2.5.2/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c
--- v2.5.2/linux/arch/sparc/mm/srmmu.c	Tue Nov 13 09:16:05 2001
+++ linux/arch/sparc/mm/srmmu.c	Tue Jan 15 10:56:35 2002
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.233 2001/11/13 00:49:27 davem Exp $
+/* $Id: srmmu.c,v 1.234 2001/12/21 04:56:15 davem Exp $
  * srmmu.c:  SRMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
@@ -536,14 +536,14 @@
 /* tsunami.S */
 extern void tsunami_flush_cache_all(void);
 extern void tsunami_flush_cache_mm(struct mm_struct *mm);
-extern void tsunami_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end);
+extern void tsunami_flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
 extern void tsunami_flush_cache_page(struct vm_area_struct *vma, unsigned long page);
 extern void tsunami_flush_page_to_ram(unsigned long page);
 extern void tsunami_flush_page_for_dma(unsigned long page);
 extern void tsunami_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr);
 extern void tsunami_flush_tlb_all(void);
 extern void tsunami_flush_tlb_mm(struct mm_struct *mm);
-extern void tsunami_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end);
+extern void tsunami_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
 extern void tsunami_flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
 extern void tsunami_setup_blockops(void);
 
@@ -582,7 +582,7 @@
 /* swift.S */
 extern void swift_flush_cache_all(void);
 extern void swift_flush_cache_mm(struct mm_struct *mm);
-extern void swift_flush_cache_range(struct mm_struct *mm,
+extern void swift_flush_cache_range(struct vm_area_struct *vma,
 				    unsigned long start, unsigned long end);
 extern void swift_flush_cache_page(struct vm_area_struct *vma, unsigned long page);
 extern void swift_flush_page_to_ram(unsigned long page);
@@ -590,7 +590,7 @@
 extern void swift_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr);
 extern void swift_flush_tlb_all(void);
 extern void swift_flush_tlb_mm(struct mm_struct *mm);
-extern void swift_flush_tlb_range(struct mm_struct *mm,
+extern void swift_flush_tlb_range(struct vm_area_struct *vma,
 				  unsigned long start, unsigned long end);
 extern void swift_flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
 
@@ -686,8 +686,9 @@
 	FLUSH_END
 }
 
-static void cypress_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+static void cypress_flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
 	register unsigned long a, b, c, d, e, f, g;
 	unsigned long flags, faddr;
 	int octx;
@@ -827,8 +828,9 @@
 	FLUSH_END
 }
 
-static void cypress_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+static void cypress_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long size;
 
 	FLUSH_BEGIN(mm)
@@ -870,7 +872,7 @@
 /* viking.S */
 extern void viking_flush_cache_all(void);
 extern void viking_flush_cache_mm(struct mm_struct *mm);
-extern void viking_flush_cache_range(struct mm_struct *mm, unsigned long start,
+extern void viking_flush_cache_range(struct vm_area_struct *vma, unsigned long start,
 				     unsigned long end);
 extern void viking_flush_cache_page(struct vm_area_struct *vma,
 				    unsigned long page);
@@ -881,13 +883,13 @@
 extern void viking_mxcc_flush_page(unsigned long page);
 extern void viking_flush_tlb_all(void);
 extern void viking_flush_tlb_mm(struct mm_struct *mm);
-extern void viking_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+extern void viking_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 				   unsigned long end);
 extern void viking_flush_tlb_page(struct vm_area_struct *vma,
 				  unsigned long page);
 extern void sun4dsmp_flush_tlb_all(void);
 extern void sun4dsmp_flush_tlb_mm(struct mm_struct *mm);
-extern void sun4dsmp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+extern void sun4dsmp_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 				   unsigned long end);
 extern void sun4dsmp_flush_tlb_page(struct vm_area_struct *vma,
 				  unsigned long page);
@@ -895,14 +897,14 @@
 /* hypersparc.S */
 extern void hypersparc_flush_cache_all(void);
 extern void hypersparc_flush_cache_mm(struct mm_struct *mm);
-extern void hypersparc_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end);
+extern void hypersparc_flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
 extern void hypersparc_flush_cache_page(struct vm_area_struct *vma, unsigned long page);
 extern void hypersparc_flush_page_to_ram(unsigned long page);
 extern void hypersparc_flush_page_for_dma(unsigned long page);
 extern void hypersparc_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr);
 extern void hypersparc_flush_tlb_all(void);
 extern void hypersparc_flush_tlb_mm(struct mm_struct *mm);
-extern void hypersparc_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end);
+extern void hypersparc_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
 extern void hypersparc_flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
 extern void hypersparc_setup_blockops(void);
 
@@ -1559,8 +1561,10 @@
 	FLUSH_END
 }
 
-static void turbosparc_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+static void turbosparc_flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
+
 	FLUSH_BEGIN(mm)
 	flush_user_windows();
 	turbosparc_idflash_clear();
@@ -1610,8 +1614,10 @@
 	FLUSH_END
 }
 
-static void turbosparc_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+static void turbosparc_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
+
 	FLUSH_BEGIN(mm)
 	srmmu_flush_whole_tlb();
 	FLUSH_END
diff -u --recursive --new-file v2.5.2/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c
--- v2.5.2/linux/arch/sparc/mm/sun4c.c	Tue Nov 13 09:16:05 2001
+++ linux/arch/sparc/mm/sun4c.c	Tue Jan 15 10:56:35 2002
@@ -1,4 +1,4 @@
-/* $Id: sun4c.c,v 1.210 2001/11/13 03:27:47 davem Exp $
+/* $Id: sun4c.c,v 1.212 2001/12/21 04:56:15 davem Exp $
  * sun4c.c: Doing in software what should be done in hardware.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -1337,7 +1337,7 @@
 static void sun4c_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
 {
 	while (sz >= 0) {
-		sg[sz].dvma_address = (__u32)sun4c_lockarea(sg[sz].address, sg[sz].length);
+		sg[sz].dvma_address = (__u32)sun4c_lockarea(page_address(sg[sz].page) + sg[sz].offset, sg[sz].length);
 		sg[sz].dvma_length = sg[sz].length;
 		sz--;
 	}
@@ -1484,8 +1484,9 @@
 	}
 }
 
-static void sun4c_flush_cache_range_hw(struct mm_struct *mm, unsigned long start, unsigned long end)
+static void sun4c_flush_cache_range_hw(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
 	int new_ctx = mm->context;
 	
 	if (new_ctx != NO_CONTEXT) {
@@ -1608,8 +1609,9 @@
 	}
 }
 
-static void sun4c_flush_cache_range_sw(struct mm_struct *mm, unsigned long start, unsigned long end)
+static void sun4c_flush_cache_range_sw(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
 	int new_ctx = mm->context;
 
 	if (new_ctx != NO_CONTEXT) {
@@ -1765,8 +1767,9 @@
 	}
 }
 
-static void sun4c_flush_tlb_range_hw(struct mm_struct *mm, unsigned long start, unsigned long end)
+static void sun4c_flush_tlb_range_hw(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
 	int new_ctx = mm->context;
 
 	if (new_ctx != NO_CONTEXT) {
@@ -1848,8 +1851,9 @@
 	}
 }
 
-static void sun4c_flush_tlb_range_sw(struct mm_struct *mm, unsigned long start, unsigned long end)
+static void sun4c_flush_tlb_range_sw(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
 	int new_ctx = mm->context;
 
 	if (new_ctx != NO_CONTEXT) {
diff -u --recursive --new-file v2.5.2/linux/arch/sparc/mm/swift.S linux/arch/sparc/mm/swift.S
--- v2.5.2/linux/arch/sparc/mm/swift.S	Tue Jul 18 12:29:47 2000
+++ linux/arch/sparc/mm/swift.S	Tue Jan 15 10:56:35 2002
@@ -1,4 +1,4 @@
-/* $Id: swift.S,v 1.7 2000/07/16 21:48:52 anton Exp $
+/* $Id: swift.S,v 1.9 2002/01/08 11:11:59 davem Exp $
  * swift.S: MicroSparc-II mmu/cache operations.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -108,6 +108,7 @@
 
 	.globl	swift_flush_cache_range
 swift_flush_cache_range:
+	ld	[%o0 + 0x0], %o0		/* XXX vma->vm_mm, GROSS XXX */
 	sub	%o2, %o1, %o2
 	sethi	%hi(4096), %o3
 	cmp	%o2, %o3
@@ -222,8 +223,9 @@
 	.globl	swift_flush_tlb_mm
 	.globl	swift_flush_tlb_range
 	.globl	swift_flush_tlb_all
-swift_flush_tlb_mm:
 swift_flush_tlb_range:
+	ld	[%o0 + 0x00], %o0	/* XXX vma->vm_mm GROSS XXX */
+swift_flush_tlb_mm:
 #ifndef CONFIG_SMP
 	ld	[%o0 + AOFF_mm_context], %g2
 	cmp	%g2, -1
diff -u --recursive --new-file v2.5.2/linux/arch/sparc/mm/tsunami.S linux/arch/sparc/mm/tsunami.S
--- v2.5.2/linux/arch/sparc/mm/tsunami.S	Tue Jul 18 12:29:47 2000
+++ linux/arch/sparc/mm/tsunami.S	Tue Jan 15 10:56:35 2002
@@ -1,4 +1,4 @@
-/* $Id: tsunami.S,v 1.6 2000/07/16 21:48:52 anton Exp $
+/* $Id: tsunami.S,v 1.7 2001/12/21 04:56:15 davem Exp $
  * tsunami.S: High speed MicroSparc-I mmu/cache operations.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -23,9 +23,9 @@
 
 	/* Sliiick... */
 tsunami_flush_cache_page:
+tsunami_flush_cache_range:
 	ld	[%o0 + 0x0], %o0	/* XXX vma->vm_mm, GROSS XXX */
 tsunami_flush_cache_mm:
-tsunami_flush_cache_range:
 	ld	[%o0 + AOFF_mm_context], %g2
 #ifndef CONFIG_SMP
 	cmp	%g2, -1
@@ -47,8 +47,9 @@
 	 flush	%o1 + 4
 
 	/* More slick stuff... */
-tsunami_flush_tlb_mm:
 tsunami_flush_tlb_range:
+	ld	[%o0 + 0x00], %o0	/* XXX vma->vm_mm GROSS XXX */
+tsunami_flush_tlb_mm:
 #ifndef CONFIG_SMP
 	ld	[%o0 + AOFF_mm_context], %g2
 	cmp	%g2, -1
diff -u --recursive --new-file v2.5.2/linux/arch/sparc/mm/viking.S linux/arch/sparc/mm/viking.S
--- v2.5.2/linux/arch/sparc/mm/viking.S	Tue Jul 18 12:29:47 2000
+++ linux/arch/sparc/mm/viking.S	Tue Jan 15 10:56:35 2002
@@ -1,4 +1,4 @@
-/* $Id: viking.S,v 1.18 2000/07/16 21:48:52 anton Exp $
+/* $Id: viking.S,v 1.19 2001/12/21 04:56:15 davem Exp $
  * viking.S: High speed Viking cache/mmu operations
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -108,11 +108,11 @@
 	 nop
 
 viking_flush_cache_page:
+viking_flush_cache_range:
 #ifndef CONFIG_SMP
 	ld	[%o0 + 0x0], %o0		/* XXX vma->vm_mm, GROSS XXX */
 #endif
 viking_flush_cache_mm:
-viking_flush_cache_range:
 #ifndef CONFIG_SMP
 	ld	[%o0 + AOFF_mm_context], %g1
 	cmp	%g1, -1
@@ -150,6 +150,7 @@
 #endif
 
 viking_flush_tlb_range:
+	ld	[%o0 + 0x00], %o0	/* XXX vma->vm_mm GROSS XXX */
 	mov	SRMMU_CTX_REG, %g1
 	ld	[%o0 + AOFF_mm_context], %o3
 	lda	[%g1] ASI_M_MMUREGS, %g5
@@ -240,6 +241,7 @@
 	tst	%g5
 	bne	3f
 	 mov	SRMMU_CTX_REG, %g1
+	ld	[%o0 + 0x00], %o0	/* XXX vma->vm_mm GROSS XXX */
 	ld	[%o0 + AOFF_mm_context], %o3
 	lda	[%g1] ASI_M_MMUREGS, %g5
 	sethi	%hi(~((1 << SRMMU_PGDIR_SHIFT) - 1)), %o4
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/config.in linux/arch/sparc64/config.in
--- v2.5.2/linux/arch/sparc64/config.in	Mon Jan 14 18:25:08 2002
+++ linux/arch/sparc64/config.in	Tue Jan 15 10:52:11 2002
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.156 2001/11/30 00:17:32 davem Exp $
+# $Id: config.in,v 1.157 2002/01/15 06:57:41 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- v2.5.2/linux/arch/sparc64/defconfig	Mon Jan 14 18:25:08 2002
+++ linux/arch/sparc64/defconfig	Tue Jan 15 10:52:11 2002
@@ -869,3 +869,8 @@
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_BUGVERBOSE is not set
 # CONFIG_DEBUG_DCFLUSH is not set
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/kernel/head.S linux/arch/sparc64/kernel/head.S
--- v2.5.2/linux/arch/sparc64/kernel/head.S	Sat Oct  6 08:50:28 2001
+++ linux/arch/sparc64/kernel/head.S	Tue Jan 15 10:52:11 2002
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.82 2001/10/04 23:37:04 davem Exp $
+/* $Id: head.S,v 1.86 2001/12/05 01:02:16 davem Exp $
  * head.S: Initial boot code for the Sparc64 port of Linux.
  *
  * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -201,7 +201,7 @@
 	 add	%l0, (1 << 3), %l0
 
 	/* Now lock the TTE we created into ITLB-0 and DTLB-0,
-	 * entry 15.
+	 * entry 15 (and maybe 14 too).
 	 */
 	sethi	%hi(KERNBASE), %g3
 	set	(0 << 16) | (15 << 3), %g7
@@ -215,6 +215,29 @@
 	membar	#Sync
 	flush	%g3
 	membar	#Sync
+	sethi	%hi(_end), %g3			/* Check for bigkernel case */
+	or	%g3, %lo(_end), %g3
+	srl	%g3, 23, %g3			/* Check if _end > 8M */
+	brz,pt	%g3, 1f
+	 sethi	%hi(KERNBASE), %g3		/* Restore for fixup code below */
+	sethi	%hi(0x400000), %g3
+	or	%g3, %lo(0x400000), %g3
+	add	%g5, %g3, %g5			/* New tte data */
+	andn	%g5, (_PAGE_G), %g5
+	sethi	%hi(KERNBASE+0x400000), %g3
+	or	%g3, %lo(KERNBASE+0x400000), %g3
+	set	(0 << 16) | (14 << 3), %g7
+	stxa	%g3, [%l7] ASI_DMMU
+	membar	#Sync
+	stxa	%g5, [%g7] ASI_DTLB_DATA_ACCESS
+	membar	#Sync
+	stxa	%g3, [%l7] ASI_IMMU
+	membar	#Sync
+	stxa	%g5, [%g7] ASI_ITLB_DATA_ACCESS
+	membar	#Sync
+	flush	%g3
+	membar	#Sync
+	sethi	%hi(KERNBASE), %g3		/* Restore for fixup code below */
 	ba,pt	%xcc, 1f
 	 nop
 
@@ -345,7 +368,7 @@
 
 
 	/* PROM never puts any TLB entries into the MMU with the lock bit
-	 * set.  So we gladly use tlb entry 63 for KERNBASE.
+	 * set.  So we gladly use tlb entry 63 for KERNBASE. And maybe 62 too.
 	 */
 
 	sethi	%hi(KERNBASE), %g3
@@ -358,7 +381,28 @@
 	membar	#Sync
 	flush	%g3
 	membar	#Sync
-	ba,pt	%xcc, 1f
+	sethi	%hi(_end), %g3			/* Check for bigkernel case */
+	or	%g3, %lo(_end), %g3
+	srl	%g3, 23, %g3			/* Check if _end > 8M */
+	brz,pt	%g3, 2f
+	 sethi	%hi(KERNBASE), %g3		/* Restore for fixup code below */
+	sethi	%hi(0x400000), %g3
+	or	%g3, %lo(0x400000), %g3
+	add	%g5, %g3, %g5			/* New tte data */
+	andn	%g5, (_PAGE_G), %g5
+	sethi	%hi(KERNBASE+0x400000), %g3
+	or	%g3, %lo(KERNBASE+0x400000), %g3
+	mov	(62 << 3), %g7
+	stxa	%g3, [%l7] ASI_DMMU
+	stxa	%g5, [%g7] ASI_DTLB_DATA_ACCESS
+	membar	#Sync
+	stxa	%g3, [%l7] ASI_IMMU
+	stxa	%g5, [%g7] ASI_ITLB_DATA_ACCESS
+	membar	#Sync
+	flush	%g3
+	membar	#Sync
+	sethi	%hi(KERNBASE), %g3		/* Restore for fixup code below */
+2:	ba,pt	%xcc, 1f
 	 nop
 1:
 	set	sun4u_init, %g2
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/kernel/init_task.c linux/arch/sparc64/kernel/init_task.c
--- v2.5.2/linux/arch/sparc64/kernel/init_task.c	Thu Sep 20 14:11:57 2001
+++ linux/arch/sparc64/kernel/init_task.c	Tue Jan 15 11:06:55 2002
@@ -1,5 +1,6 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
+#include <linux/init_task.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- v2.5.2/linux/arch/sparc64/kernel/ioctl32.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/sparc64/kernel/ioctl32.c	Tue Jan 15 10:52:11 2002
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.135 2002/01/11 08:45:38 davem Exp $
+/* $Id: ioctl32.c,v 1.136 2002/01/14 09:49:52 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
@@ -1581,12 +1581,17 @@
 	}
 
 	err |= __get_user(sbp32, &sg_io32->sbp);
-	sg_io64.sbp = kmalloc(64, GFP_KERNEL);
+	sg_io64.sbp = kmalloc(sg_io64.mx_sb_len, GFP_KERNEL);
 	if (!sg_io64.sbp) {
 		err = -ENOMEM;
 		goto out;
 	}
-	memset(sg_io64.sbp, 0, 64);
+	if (copy_from_user(sg_io64.sbp,
+			   (void *) A(sbp32),
+			   sg_io64.mx_sb_len)) {
+		err = -EFAULT;
+		goto out;
+	}
 
 	err |= __get_user(dxferp32, &sg_io32->dxferp);
 	if (sg_io64.iovec_count) {
@@ -1634,7 +1639,7 @@
 	err |= __put_user(sg_io64.resid, &sg_io32->resid);
 	err |= __put_user(sg_io64.duration, &sg_io32->duration);
 	err |= __put_user(sg_io64.info, &sg_io32->info);
-	err |= copy_to_user((void *)A(sbp32), sg_io64.sbp, 64);
+	err |= copy_to_user((void *)A(sbp32), sg_io64.sbp, sg_io64.mx_sb_len);
 	if (sg_io64.dxferp) {
 		if (sg_io64.iovec_count)
 			err |= copy_back_sg_iovec(&sg_io64, dxferp32);
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/kernel/pci.c linux/arch/sparc64/kernel/pci.c
--- v2.5.2/linux/arch/sparc64/kernel/pci.c	Wed Oct 10 23:42:46 2001
+++ linux/arch/sparc64/kernel/pci.c	Tue Jan 15 10:56:35 2002
@@ -1,4 +1,4 @@
-/* $Id: pci.c,v 1.36 2001/10/06 00:38:25 davem Exp $
+/* $Id: pci.c,v 1.39 2002/01/05 01:13:43 davem Exp $
  * pci.c: UltraSparc PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
@@ -487,7 +487,7 @@
 	/* Our io_remap_page_range takes care of this, do nothing. */
 }
 
-extern int io_remap_page_range(unsigned long from, unsigned long offset,
+extern int io_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long offset,
 			       unsigned long size, pgprot_t prot, int space);
 
 /* Perform the actual remap of the pages for a PCI device mapping, as appropriate
@@ -511,7 +511,7 @@
 	__pci_mmap_set_flags(dev, vma, mmap_state);
 	__pci_mmap_set_pgprot(dev, vma, mmap_state);
 
-	ret = io_remap_page_range(vma->vm_start,
+	ret = io_remap_page_range(vma, vma->vm_start,
 				  (vma->vm_pgoff << PAGE_SHIFT |
 				   (write_combine ? 0x1UL : 0x0UL)),
 				  vma->vm_end - vma->vm_start, vma->vm_page_prot, 0);
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/kernel/pci_common.c linux/arch/sparc64/kernel/pci_common.c
--- v2.5.2/linux/arch/sparc64/kernel/pci_common.c	Tue Aug 14 19:57:28 2001
+++ linux/arch/sparc64/kernel/pci_common.c	Tue Jan 15 10:52:11 2002
@@ -1,4 +1,4 @@
-/* $Id: pci_common.c,v 1.27 2001/08/12 13:18:22 davem Exp $
+/* $Id: pci_common.c,v 1.28 2002/01/14 05:47:02 davem Exp $
  * pci_common.c: PCI controller common support.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -183,6 +183,17 @@
 		pcp->prom_name[err] = 0;
 	else
 		pcp->prom_name[0] = 0;
+
+	err = prom_getproperty(device_prom_node,
+			       "assigned-addresses",
+			       (char *)pcp->prom_assignments,
+			       sizeof(pcp->prom_assignments));
+	if (err == 0 || err == -1)
+		pcp->num_prom_assignments = 0;
+	else
+		pcp->num_prom_assignments =
+			(err / sizeof(pcp->prom_assignments[0]));
+
 	if (strcmp(pcp->prom_name, "ebus") == 0) {
 		struct linux_prom_ebus_ranges erng[PROM_PCIRNG_MAX];
 		int iter;
@@ -208,16 +219,6 @@
 			ap->size_lo = ep->size;
 		}
 		pcp->num_prom_assignments = err;
-	} else {
-		err = prom_getproperty(device_prom_node,
-				       "assigned-addresses",
-				       (char *)pcp->prom_assignments,
-				       sizeof(pcp->prom_assignments));
-		if (err == 0 || err == -1)
-			pcp->num_prom_assignments = 0;
-		else
-			pcp->num_prom_assignments =
-				(err / sizeof(pcp->prom_assignments[0]));
 	}
 
 	fixup_obp_assignments(pdev, pcp);
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c
--- v2.5.2/linux/arch/sparc64/kernel/process.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/sparc64/kernel/process.c	Tue Jan 15 13:53:51 2002
@@ -61,7 +61,7 @@
 		 * But this requires writing back the contents of the
 		 * L2 cache etc. so implement this later. -DaveM
 		 */
-		while (!current->need_resched)
+		while (!need_resched())
 			barrier();
 
 		schedule();
@@ -80,7 +80,7 @@
 int cpu_idle(void)
 {
 	while(1) {
-		if (current->need_resched != 0) {
+		if (need_resched()) {
 			unidle_me();
 			schedule();
 			check_pgt_cache();
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c
--- v2.5.2/linux/arch/sparc64/kernel/smp.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/sparc64/kernel/smp.c	Tue Jan 15 10:56:35 2002
@@ -138,6 +138,15 @@
 {
 	int cpuid = hard_smp_processor_id();
 	unsigned long pstate;
+	extern int bigkernel;
+	extern unsigned long kern_locked_tte_data;
+
+	if (bigkernel) {
+		prom_dtlb_load(sparc64_highest_locked_tlbent()-1, 
+			kern_locked_tte_data + 0x400000, KERNBASE + 0x400000);
+		prom_itlb_load(sparc64_highest_locked_tlbent()-1, 
+			kern_locked_tte_data + 0x400000, KERNBASE + 0x400000);
+	}
 
 	inherit_locked_prom_mappings(0);
 
@@ -796,9 +805,11 @@
 	}
 }
 
-void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+void smp_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 			 unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
+
 	{
 		u32 ctx = CTX_HWBITS(mm->context);
 		int cpu = smp_processor_id();
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c
--- v2.5.2/linux/arch/sparc64/kernel/sparc64_ksyms.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/sparc64/kernel/sparc64_ksyms.c	Tue Jan 15 10:56:35 2002
@@ -88,7 +88,7 @@
 extern long sparc32_open(const char * filename, int flags, int mode);
 extern int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *));
 extern int unregister_ioctl32_conversion(unsigned int cmd);
-extern int io_remap_page_range(unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space);
+extern int io_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space);
                 
 extern int __ashrdi3(int, int);
 
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/lib/U3copy_from_user.S linux/arch/sparc64/lib/U3copy_from_user.S
--- v2.5.2/linux/arch/sparc64/lib/U3copy_from_user.S	Thu Nov  9 15:57:41 2000
+++ linux/arch/sparc64/lib/U3copy_from_user.S	Tue Jan 15 10:52:11 2002
@@ -1,4 +1,4 @@
-/* $Id: U3copy_from_user.S,v 1.3 2000/11/01 09:29:19 davem Exp $
+/* $Id: U3copy_from_user.S,v 1.4 2002/01/15 07:16:26 davem Exp $
  * U3memcpy.S: UltraSparc-III optimized copy from userspace.
  *
  * Copyright (C) 1999, 2000 David S. Miller (davem@redhat.com)
@@ -13,7 +13,7 @@
 	.section .fixup;		\
 	.align 4;			\
 99:	VISExitHalf;			\
-	ba,pt %xcc, U3cfu_fixup;	\
+	ba U3cfu_fixup;			\
 	 a, b, %o1;			\
 	.section __ex_table;		\
 	.align 4;			\
@@ -25,7 +25,7 @@
 	.section .fixup;		\
 	.align 4;			\
 99:	VISExitHalf;			\
-	ba,pt %xcc, U3cfu_fixup;	\
+	ba U3cfu_fixup;			\
 	 a, b, %o1;			\
 	.section __ex_table;		\
 	.align 4;			\
@@ -39,7 +39,7 @@
 99:	VISExitHalf;			\
 	and %o2, (0x40 - 1), %o1;	\
 	add %o1, %o4, %o1;		\
-	ba,pt %xcc, U3cfu_fixup;	\
+	ba U3cfu_fixup;			\
 	 add %o1, 0x1c0, %o1;		\
 	.section __ex_table;		\
 	.align 4;			\
@@ -54,7 +54,7 @@
 	and %o2, (0x40 - 1), %o1;	\
 	sll %g3, 6, %g3;		\
 	add %o1, 0x80, %o1;		\
-	ba,pt %xcc, U3cfu_fixup;	\
+	ba U3cfu_fixup;			\
 	 add %o1, %g3, %o1;		\
 	.section __ex_table;		\
 	.align 4;			\
@@ -68,7 +68,7 @@
 99:	VISExitHalf;			\
 	and %o2, (0x40 - 1), %o1;	\
 	add %o1, 0x40, %o1;		\
-	ba,pt %xcc, U3cfu_fixup;	\
+	ba U3cfu_fixup;			\
 	 add %o1, %g3, %o1;		\
 	.section __ex_table;		\
 	.align 4;			\
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/mm/generic.c linux/arch/sparc64/mm/generic.c
--- v2.5.2/linux/arch/sparc64/mm/generic.c	Thu Apr 12 12:10:25 2001
+++ linux/arch/sparc64/mm/generic.c	Tue Jan 15 10:56:35 2002
@@ -1,4 +1,4 @@
-/* $Id: generic.c,v 1.17 2001/04/09 04:08:06 davem Exp $
+/* $Id: generic.c,v 1.18 2001/12/21 04:56:15 davem Exp $
  * generic.c: Generic Sparc mm routines that are not dependent upon
  *            MMU type but are Sparc specific.
  *
@@ -111,18 +111,18 @@
 	return 0;
 }
 
-int io_remap_page_range(unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space)
+int io_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space)
 {
 	int error = 0;
 	pgd_t * dir;
 	unsigned long beg = from;
 	unsigned long end = from + size;
-	struct mm_struct *mm = current->mm;
+	struct mm_struct *mm = vma->vm_mm;
 
 	prot = __pgprot(pg_iobits);
 	offset -= from;
 	dir = pgd_offset(mm, from);
-	flush_cache_range(mm, beg, end);
+	flush_cache_range(vma, beg, end);
 
 	spin_lock(&mm->page_table_lock);
 	while (from < end) {
@@ -138,6 +138,6 @@
 	}
 	spin_unlock(&mm->page_table_lock);
 
-	flush_tlb_range(current->mm, beg, end);
+	flush_tlb_range(vma, beg, end);
 	return error;
 }
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c
--- v2.5.2/linux/arch/sparc64/mm/init.c	Mon Jan 14 18:25:08 2002
+++ linux/arch/sparc64/mm/init.c	Tue Jan 15 10:56:35 2002
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.202 2001/11/13 00:49:28 davem Exp $
+/*  $Id: init.c,v 1.208 2001/12/21 04:56:15 davem Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
@@ -63,6 +63,8 @@
 
 struct page *mem_map_zero;
 
+int bigkernel = 0;
+
 int do_check_pgt_cache(int low, int high)
 {
         int freed = 0;
@@ -226,6 +228,82 @@
 	}
 }
 
+/* When shared+writable mmaps of files go away, we lose all dirty
+ * page state, so we have to deal with D-cache aliasing here.
+ *
+ * This code relies on the fact that flush_cache_range() is always
+ * called for an area composed by a single VMA.  It also assumes that
+ * the MM's page_table_lock is held.
+ */
+static inline void flush_cache_pte_range(struct mm_struct *mm, pmd_t *pmd, unsigned long address, unsigned long size)
+{
+	unsigned long offset;
+	pte_t *ptep;
+
+	if (pmd_none(*pmd))
+		return;
+	ptep = pte_offset(pmd, address);
+	offset = address & ~PMD_MASK;
+	if (offset + size > PMD_SIZE)
+		size = PMD_SIZE - offset;
+	size &= PAGE_MASK;
+	for (offset = 0; offset < size; ptep++, offset += PAGE_SIZE) {
+		pte_t pte = *ptep;
+
+		if (pte_none(pte))
+			continue;
+
+		if (pte_present(pte) && pte_dirty(pte)) {
+			struct page *page = pte_page(pte);
+			unsigned long pgaddr, uaddr;
+
+			if (!VALID_PAGE(page) || PageReserved(page) || !page->mapping)
+				continue;
+			pgaddr = (unsigned long) page_address(page);
+			uaddr = address + offset;
+			if ((pgaddr ^ uaddr) & (1 << 13))
+				flush_dcache_page_all(mm, page);
+		}
+	}
+}
+
+static inline void flush_cache_pmd_range(struct mm_struct *mm, pgd_t *dir, unsigned long address, unsigned long size)
+{
+	pmd_t *pmd;
+	unsigned long end;
+
+	if (pgd_none(*dir))
+		return;
+	pmd = pmd_offset(dir, address);
+	end = address + size;
+	if (end > ((address + PGDIR_SIZE) & PGDIR_MASK))
+		end = ((address + PGDIR_SIZE) & PGDIR_MASK);
+	do {
+		flush_cache_pte_range(mm, pmd, address, end - address);
+		address = (address + PMD_SIZE) & PMD_MASK;
+		pmd++;
+	} while (address < end);
+}
+
+void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
+{
+	struct mm_struct *mm = vma->vm_mm;
+	pgd_t *dir = pgd_offset(mm, start);
+
+	if (mm == current->mm)
+		flushw_user();
+
+	if (vma->vm_file == NULL ||
+	    ((vma->vm_flags & (VM_SHARED|VM_WRITE)) != (VM_SHARED|VM_WRITE)))
+		return;
+
+	do {
+		flush_cache_pmd_range(mm, dir, start, end - start);
+		start = (start + PGDIR_SIZE) & PGDIR_MASK;
+		dir++;
+	} while (start && (start < end));
+}
+
 void flush_icache_range(unsigned long start, unsigned long end)
 {
 	/* Cheetah has coherent I-cache. */
@@ -505,6 +583,10 @@
 		   (unsigned long) KERNBASE,
 		   prom_get_mmu_ihandle());
 
+	if (bigkernel)
+		remap_func(((tte_data + 0x400000) & _PAGE_PADDR),
+			(unsigned long) KERNBASE + 0x400000, prom_get_mmu_ihandle());
+
 	/* Flush out that temporary mapping. */
 	spitfire_flush_dtlb_nucleus_page(0x0);
 	spitfire_flush_itlb_nucleus_page(0x0);
@@ -512,6 +594,12 @@
 	/* Now lock us back into the TLBs via OBP. */
 	prom_dtlb_load(sparc64_highest_locked_tlbent(), tte_data, tte_vaddr);
 	prom_itlb_load(sparc64_highest_locked_tlbent(), tte_data, tte_vaddr);
+	if (bigkernel) {
+		prom_dtlb_load(sparc64_highest_locked_tlbent()-1, tte_data + 0x400000, 
+								tte_vaddr + 0x400000);
+		prom_itlb_load(sparc64_highest_locked_tlbent()-1, tte_data + 0x400000, 
+								tte_vaddr + 0x400000);
+	}
 
 	/* Re-read translations property. */
 	if ((n = prom_getproperty(node, "translations", (char *)trans, tsz)) == -1) {
@@ -528,6 +616,8 @@
 			unsigned long avoid_start = (unsigned long) KERNBASE;
 			unsigned long avoid_end = avoid_start + (4 * 1024 * 1024);
 
+			if (bigkernel)
+				avoid_end += (4 * 1024 * 1024);
 			if (vaddr < avoid_start) {
 				unsigned long top = vaddr + size;
 
@@ -714,7 +804,8 @@
 		}
 	}
 	if (tlb_type == spitfire) {
-		for (i = 0; i < SPITFIRE_HIGHEST_LOCKED_TLBENT; i++) {
+		int high = SPITFIRE_HIGHEST_LOCKED_TLBENT - bigkernel;
+		for (i = 0; i < high; i++) {
 			unsigned long data;
 
 			/* Spitfire Errata #32 workaround */
@@ -752,7 +843,7 @@
 			}
 		}
 
-		for (i = 0; i < SPITFIRE_HIGHEST_LOCKED_TLBENT; i++) {
+		for (i = 0; i < high; i++) {
 			unsigned long data;
 
 			/* Spitfire Errata #32 workaround */
@@ -790,7 +881,9 @@
 			}
 		}
 	} else if (tlb_type == cheetah) {
-		for (i = 0; i < CHEETAH_HIGHEST_LOCKED_TLBENT; i++) {
+		int high = CHEETAH_HIGHEST_LOCKED_TLBENT - bigkernel;
+
+		for (i = 0; i < high; i++) {
 			unsigned long data;
 
 			data = cheetah_get_ldtlb_data(i);
@@ -814,7 +907,7 @@
 			}
 		}
 
-		for (i = 0; i < CHEETAH_HIGHEST_LOCKED_TLBENT; i++) {
+		for (i = 0; i < high; i++) {
 			unsigned long data;
 
 			data = cheetah_get_litlb_data(i);
@@ -1282,6 +1375,8 @@
 	set_bit(0, mmu_context_bmap);
 
 	real_end = (unsigned long)&_end;
+	if ((real_end > ((unsigned long)KERNBASE + 0x400000)))
+		bigkernel = 1;
 #ifdef CONFIG_BLK_DEV_INITRD
 	if (sparc_ramdisk_image)
 		real_end = (PAGE_ALIGN(real_end) + PAGE_ALIGN(sparc_ramdisk_size));
diff -u --recursive --new-file v2.5.2/linux/arch/sparc64/mm/modutil.c linux/arch/sparc64/mm/modutil.c
--- v2.5.2/linux/arch/sparc64/mm/modutil.c	Tue Aug 28 07:09:44 2001
+++ linux/arch/sparc64/mm/modutil.c	Tue Jan 15 10:52:11 2002
@@ -1,4 +1,4 @@
-/*  $Id: modutil.c,v 1.9 2001/08/14 22:10:56 davem Exp $
+/*  $Id: modutil.c,v 1.11 2001/12/05 06:05:35 davem Exp $
  *  arch/sparc64/mm/modutil.c
  *
  *  Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -10,10 +10,6 @@
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
-
-#define  MODULES_VADDR	0x0000000001000000ULL  /* Where to map modules */
-#define  MODULES_LEN	0x000000007f000000ULL
-#define  MODULES_END	0x0000000080000000ULL
 
 static struct vm_struct * modvmlist = NULL;
 
diff -u --recursive --new-file v2.5.2/linux/drivers/block/cciss.c linux/drivers/block/cciss.c
--- v2.5.2/linux/drivers/block/cciss.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/block/cciss.c	Fri Jan 18 14:05:55 2002
@@ -64,6 +64,8 @@
                         0x0E11, 0x4080, 0, 0, 0},
 	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB,
                         0x0E11, 0x4082, 0, 0, 0},
+	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB,
+                        0x0E11, 0x4083, 0, 0, 0},
 	{0,}
 };
 MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
@@ -78,6 +80,7 @@
 	{ 0x40700E11, "Smart Array 5300",	&SA5_access },
 	{ 0x40800E11, "Smart Array 5i", &SA5B_access},
 	{ 0x40820E11, "Smart Array 532", &SA5B_access},
+	{ 0x40830E11, "Smart Array 5312", &SA5B_access},
 };
 
 /* How long to wait (in millesconds) for board to go into simple mode */
@@ -102,6 +105,8 @@
 static int revalidate_allvol(kdev_t dev);
 static int revalidate_logvol(kdev_t dev, int maxusage);
 static int frevalidate_logvol(kdev_t dev);
+static int deregister_disk(int ctlr, int logvol);
+static int register_new_disk(kdev_t dev, int cltr);
 
 static void cciss_getgeometry(int cntl_num);
 
@@ -148,6 +153,7 @@
                 "       Memory Address: 0x%08lx\n"
                 "       IRQ: %d\n"
                 "       Logical drives: %d\n"
+		"       Highest Logical Volume ID: %d\n"
                 "       Current Q depth: %d\n"
                 "       Max Q depth since init: %d\n"
 		"       Max # commands on controller since init: %d\n"
@@ -159,12 +165,15 @@
                 (unsigned long)h->vaddr,
                 (unsigned int)h->intr,
                 h->num_luns, 
+                h->highest_lun, 
                 h->Qdepth, h->maxQsinceinit, h->max_outstanding, h->maxSG);
 
         pos += size; len += size;
 	cciss_proc_tape_report(ctlr, buffer, &pos, &len);
-	for(i=0; i<h->num_luns; i++) {
+	for(i=0; i<h->highest_lun; i++) {
                 drv = &h->drv[i];
+		if (drv->block_size == 0)
+			continue;
                 size = sprintf(buffer+len, "cciss/c%dd%d: blksz=%d nr_blocks=%d\n",
                                 ctlr, i, drv->block_size, drv->nr_blocks);
                 pos += size; len += size;
@@ -344,9 +353,10 @@
 		for(j=0; j<MAX_PART; j++)
 			hba[ctlr]->blocksizes[(i<<NWD_SHIFT) + j] = 1024; 
 
-		hba[ctlr]->gendisk.nr_real++;
+		//hba[ctlr]->gendisk.nr_real++;
 		(BLK_DEFAULT_QUEUE(MAJOR_NR + ctlr))->hardsect_size = drv->block_size;
 	}
+	hba[ctlr]->gendisk.nr_real = hba[ctlr]->highest_lun+1;
 }
 /*
  * Open.  Make sure the device is really there.
@@ -416,24 +426,42 @@
 	switch(cmd) {
 	case HDIO_GETGEO:
 	{
-		struct hd_geometry *geo = (struct hd_geometry *)arg;
-		int diskinfo[4];
-
-		if (hba[ctlr]->drv[dsk].cylinders) {
-			diskinfo[0] = hba[ctlr]->drv[dsk].heads;
-			diskinfo[1] = hba[ctlr]->drv[dsk].sectors;
-			diskinfo[2] = hba[ctlr]->drv[dsk].cylinders;
-		} else {
-			diskinfo[0] = 0xff;
-			diskinfo[1] = 0x3f;
-			diskinfo[2] = hba[ctlr]->drv[dsk].nr_blocks / (0xff*0x3f);
-		}
-		put_user(diskinfo[0], &geo->heads);
-		put_user(diskinfo[1], &geo->sectors);
-		put_user(diskinfo[2], &geo->cylinders);
-		put_user(get_start_sect(inode->i_rdev), &geo->start);
-		return 0;
+                struct hd_geometry driver_geo;
+                if (hba[ctlr]->drv[dsk].cylinders) {
+                        driver_geo.heads = hba[ctlr]->drv[dsk].heads;
+                        driver_geo.sectors = hba[ctlr]->drv[dsk].sectors;
+                        driver_geo.cylinders = hba[ctlr]->drv[dsk].cylinders;
+                } else {
+                        driver_geo.heads = 0xff;
+                        driver_geo.sectors = 0x3f;
+                        driver_geo.cylinders = hba[ctlr]->drv[dsk].nr_blocks / (0xff*0x3f);
+                }
+                driver_geo.start=
+                        hba[ctlr]->hd[minor(inode->i_rdev)].start_sect;
+                if (copy_to_user((void *) arg, &driver_geo,
+                                sizeof( struct hd_geometry)))
+                        return  -EFAULT;
+                return(0);
 	}
+	case HDIO_GETGEO_BIG:
+        {
+		struct hd_big_geometry driver_geo;
+                if (hba[ctlr]->drv[dsk].cylinders) {
+                        driver_geo.heads = hba[ctlr]->drv[dsk].heads;
+                        driver_geo.sectors = hba[ctlr]->drv[dsk].sectors;
+                        driver_geo.cylinders = hba[ctlr]->drv[dsk].cylinders;
+                } else {
+                        driver_geo.heads = 0xff;
+                        driver_geo.sectors = 0x3f;
+                        driver_geo.cylinders = hba[ctlr]->drv[dsk].nr_blocks / (0xff*0x3f);
+              	}
+	      	driver_geo.start= 
+			hba[ctlr]->hd[minor(inode->i_rdev)].start_sect;
+		if (copy_to_user((void *) arg, &driver_geo,  
+				sizeof( struct hd_big_geometry)))
+                        return  -EFAULT;
+                return(0);
+        }
 	case BLKRRPART:
 		return revalidate_logvol(inode->i_rdev, 1);
 	case BLKGETSIZE:
@@ -603,7 +631,14 @@
 
 	case CCISS_REVALIDVOLS:
                 return( revalidate_allvol(inode->i_rdev));
-	
+
+	case CCISS_DEREGDISK:
+		return( deregister_disk(ctlr,dsk));
+
+	case CCISS_REGNEWD:
+	{
+		return(register_new_disk(inode->i_rdev, ctlr));
+	}	
 	case CCISS_PASSTHRU:
 	{
 		IOCTL_Command_struct iocommand;
@@ -827,8 +862,503 @@
         return 0;
 }
 
+static int deregister_disk(int ctlr, int logvol)
+{
+	unsigned long flags;
+	struct gendisk *gdev = &(hba[ctlr]->gendisk);
+	ctlr_info_t  *h = hba[ctlr];
+	int start, max_p, i;	
+
+
+	if (!capable(CAP_SYS_RAWIO))
+		return -EPERM;
+
+	spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+	/* make sure logical volume is NOT is use */
+	if( h->drv[logvol].usage_count > 1)
+	{
+		spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+                return -EBUSY;
+	}
+	h->drv[logvol].usage_count++;
+	spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+
+	/* invalidate the devices and deregister the disk */ 
+	max_p = 1 << gdev->minor_shift;
+	start = logvol << gdev->minor_shift;
+	for (i=max_p-1; i>=0; i--)
+	{
+		int minor = start+i;
+		kdev_t kdev = mk_kdev(MAJOR_NR+ctlr, minor);
+		// printk("invalidating( %d %d)\n", ctlr, minor);
+		invalidate_device(kdev, 1);
+		/* so open will now fail */
+		h->sizes[minor] = 0;
+		/* so it will no longer appear in /proc/partitions */ 
+		gdev->part[minor].start_sect = 0;
+		gdev->part[minor].nr_sects = 0;	
+	}
+	/* check to see if it was the last disk */
+	if (logvol == h->highest_lun)
+	{
+		/* if so, find the new hightest lun */
+		int i, newhighest =-1;
+		for(i=0; i<h->highest_lun; i++)
+		{
+			/* if the disk has size > 0, it is available */
+			if (h->sizes[i << gdev->minor_shift] != 0)
+				newhighest = i;
+		}
+		h->highest_lun = newhighest;
+				
+	}
+	--h->num_luns;
+	gdev->nr_real = h->highest_lun+1; 
+	/* zero out the disk size info */ 
+	h->drv[logvol].nr_blocks = 0;
+	h->drv[logvol].block_size = 0;
+	h->drv[logvol].LunID = 0;
+	return(0);
+}
+static int sendcmd_withirq(__u8	cmd,
+	int	ctlr,
+	void	*buff,
+	size_t	size,
+	unsigned int use_unit_num,
+	unsigned int log_unit,
+	__u8	page_code )
+{
+	ctlr_info_t *h = hba[ctlr];
+	CommandList_struct *c;
+	u64bit	buff_dma_handle;
+	unsigned long flags;
+	int return_status = IO_OK;
+	
+	if ((c = cmd_alloc(h , 0)) == NULL)
+	{
+		return -ENOMEM;
+	}
+	// Fill in the command type 
+	c->cmd_type = CMD_IOCTL_PEND;
+	// Fill in Command Header 
+	c->Header.ReplyQueue = 0;  // unused in simple mode
+	if( buff != NULL) 	// buffer to fill 
+	{
+		c->Header.SGList = 1;
+		c->Header.SGTotal= 1;
+	} else	// no buffers to fill  
+	{
+		c->Header.SGList = 0;
+                c->Header.SGTotal= 0;
+	}
+	c->Header.Tag.lower = c->busaddr;  // use the kernel address the cmd block for tag
+	// Fill in Request block 	
+	switch(cmd)
+	{
+		case  CISS_INQUIRY:
+			/* If the logical unit number is 0 then, this is going
+				to controller so It's a physical command
+				mode = 0 target = 0.
+				So we have nothing to write. 
+				Otherwise 
+				mode = 1  target = LUNID
+			*/
+			if(use_unit_num != 0)
+			{
+				c->Header.LUN.LogDev.VolId=
+                                	hba[ctlr]->drv[log_unit].LunID;
+                        	c->Header.LUN.LogDev.Mode = 1;
+			}
+			if(page_code != 0)
+			{
+				c->Request.CDB[1] = 0x01;
+				c->Request.CDB[2] = page_code;
+			}
+			c->Request.CDBLen = 6;
+			c->Request.Type.Type =  TYPE_CMD; // It is a command. 
+			c->Request.Type.Attribute = ATTR_SIMPLE;  
+			c->Request.Type.Direction = XFER_READ; // Read 
+			c->Request.Timeout = 0; // Don't time out 
+			c->Request.CDB[0] =  CISS_INQUIRY;
+			c->Request.CDB[4] = size  & 0xFF;  
+		break;
+	case CISS_REPORT_LOG:
+                        /* Talking to controller so It's a physical command
+                                mode = 00 target = 0.
+                                So we have nothing to write.
+                        */
+                        c->Request.CDBLen = 12;
+                        c->Request.Type.Type =  TYPE_CMD; // It is a command.
+                        c->Request.Type.Attribute = ATTR_SIMPLE; 
+                        c->Request.Type.Direction = XFER_READ; // Read
+                        c->Request.Timeout = 0; // Don't time out
+                        c->Request.CDB[0] = CISS_REPORT_LOG;
+                        c->Request.CDB[6] = (size >> 24) & 0xFF;  //MSB
+                        c->Request.CDB[7] = (size >> 16) & 0xFF;
+                        c->Request.CDB[8] = (size >> 8) & 0xFF;
+                        c->Request.CDB[9] = size & 0xFF;
+                break;
+	case CCISS_READ_CAPACITY:
+			c->Header.LUN.LogDev.VolId= 
+				hba[ctlr]->drv[log_unit].LunID;
+			c->Header.LUN.LogDev.Mode = 1;
+			c->Request.CDBLen = 10;
+                        c->Request.Type.Type =  TYPE_CMD; // It is a command.
+                        c->Request.Type.Attribute = ATTR_SIMPLE; 
+                        c->Request.Type.Direction = XFER_READ; // Read
+                        c->Request.Timeout = 0; // Don't time out
+                        c->Request.CDB[0] = CCISS_READ_CAPACITY;
+		break;
+		default:
+			printk(KERN_WARNING
+				"cciss:  Unknown Command 0x%c sent attempted\n", cmd);
+			cmd_free(h, c, 1);
+			return(IO_ERROR);
+	};
+
+	// Fill in the scatter gather information
+	if (size > 0 ) 
+	{
+		buff_dma_handle.val = (__u64) pci_map_single( h->pdev, 
+			buff, size, PCI_DMA_BIDIRECTIONAL);
+		c->SG[0].Addr.lower = buff_dma_handle.val32.lower;
+		c->SG[0].Addr.upper = buff_dma_handle.val32.upper;
+		c->SG[0].Len = size;
+		c->SG[0].Ext = 0;  // we are not chaining
+	}
+	
+	/* Put the request on the tail of the queue and send it */
+	spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+	addQ(&h->reqQ, c);
+	h->Qdepth++;
+	start_io(h);
+	spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+	
+	/* wait for completion */ 
+	while(c->cmd_type != CMD_IOCTL_DONE)
+		schedule_timeout(1);
+	/* unlock the buffers from DMA */
+        pci_unmap_single( h->pdev, (dma_addr_t) buff_dma_handle.val,
+                	size, PCI_DMA_BIDIRECTIONAL);
+
+	if(c->err_info->CommandStatus != 0) 
+	{ /* an error has occurred */ 
+		switch(c->err_info->CommandStatus)
+		{
+			case CMD_TARGET_STATUS:
+				printk(KERN_WARNING "cciss: cmd %p has "
+					" completed with errors\n", c);
+				if( c->err_info->ScsiStatus)
+                		{
+                    			printk(KERN_WARNING "cciss: cmd %p "
+					"has SCSI Status = %x\n",
+                        			c,  
+						c->err_info->ScsiStatus);
+                		}
+
+			break;
+			case CMD_DATA_UNDERRUN:
+			case CMD_DATA_OVERRUN:
+			/* expected for inquire and report lun commands */
+			break;
+			case CMD_INVALID:
+				printk(KERN_WARNING "cciss: Cmd %p is "
+					"reported invalid\n", c);
+				return_status = IO_ERROR;
+			break;
+			case CMD_PROTOCOL_ERR:
+                                printk(KERN_WARNING "cciss: cmd %p has "
+					"protocol error \n", c);
+                                return_status = IO_ERROR;
+                        break;
+case CMD_HARDWARE_ERR:
+                                printk(KERN_WARNING "cciss: cmd %p had " 
+                                        " hardware error\n", c);
+                                return_status = IO_ERROR;
+                        break;
+			case CMD_CONNECTION_LOST:
+				printk(KERN_WARNING "cciss: cmd %p had "
+					"connection lost\n", c);
+				return_status = IO_ERROR;
+			break;
+			case CMD_ABORTED:
+				printk(KERN_WARNING "cciss: cmd %p was "
+					"aborted\n", c);
+				return_status = IO_ERROR;
+			break;
+			case CMD_ABORT_FAILED:
+				printk(KERN_WARNING "cciss: cmd %p reports "
+					"abort failed\n", c);
+				return_status = IO_ERROR;
+			break;
+			case CMD_UNSOLICITED_ABORT:
+				printk(KERN_WARNING "cciss: cmd %p aborted "
+					"do to an unsolicited abort\n", c);
+				return_status = IO_ERROR;
+
 
+			break;
+			default:
+				printk(KERN_WARNING "cciss: cmd %p returned "
+					"unknown status %x\n", c, 
+						c->err_info->CommandStatus); 
+				return_status = IO_ERROR;
+		}
+	}	
+	cmd_free(h, c, 0);
+        return(return_status);
 
+}
+static int register_new_disk(kdev_t dev, int ctlr)
+{
+        struct gendisk *gdev = &(hba[ctlr]->gendisk);
+        ctlr_info_t  *h = hba[ctlr];
+        int start, max_p, i;
+	int num_luns;
+	int logvol;
+	int new_lun_found = 0;
+	int new_lun_index = 0;
+	int free_index_found = 0;
+	int free_index = 0;
+	ReportLunData_struct *ld_buff;
+	ReadCapdata_struct *size_buff;
+	InquiryData_struct *inq_buff;
+	int return_code;
+	int listlength = 0;
+	__u32 lunid = 0;
+	unsigned int block_size;
+	unsigned int total_size;
+
+        if (!capable(CAP_SYS_RAWIO))
+                return -EPERM;
+	/* if we have no space in our disk array left to add anything */
+	if(  h->num_luns >= CISS_MAX_LUN)
+		return -EINVAL;
+	
+	ld_buff = kmalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
+	if (ld_buff == NULL)
+	{
+		printk(KERN_ERR "cciss: out of memory\n");
+		return -1;
+	}
+	memset(ld_buff, 0, sizeof(ReportLunData_struct));
+	size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
+        if (size_buff == NULL)
+        {
+                printk(KERN_ERR "cciss: out of memory\n");
+		kfree(ld_buff);
+                return -1;
+        }
+	inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
+        if (inq_buff == NULL)
+        {
+                printk(KERN_ERR "cciss: out of memory\n");
+                kfree(ld_buff);
+		kfree(size_buff);
+                return -1;
+        }
+	
+	return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff, 
+			sizeof(ReportLunData_struct), 0, 0, 0 );
+
+	if( return_code == IO_OK)
+	{
+		
+		// printk("LUN Data\n--------------------------\n");
+
+		listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24;
+		listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16;
+		listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8;	
+		listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]);
+	} else /* reading number of logical volumes failed */
+	{
+		printk(KERN_WARNING "cciss: report logical volume"
+			" command failed\n");
+		listlength = 0;
+		return -1;
+	}
+	num_luns = listlength / 8; // 8 bytes pre entry
+	if (num_luns > CISS_MAX_LUN)
+	{
+		num_luns = CISS_MAX_LUN;
+	}
+#ifdef CCISS_DEBUG
+	printk(KERN_DEBUG "Length = %x %x %x %x = %d\n", ld_buff->LUNListLength[0],
+		ld_buff->LUNListLength[1], ld_buff->LUNListLength[2],
+		ld_buff->LUNListLength[3],  num_luns);
+#endif 
+	for(i=0; i<  num_luns; i++)
+	{
+		int j;
+		int lunID_found = 0;
+
+	  	lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) << 24;
+        	lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) << 16;
+        	lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) << 8;
+        	lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]);
+		
+ 		/* check to see if this is a new lun */ 
+		for(j=0; j <= h->highest_lun; j++)
+		{
+#ifdef CCISS_DEBUG
+			printk("Checking %d %x against %x\n", j,h->drv[j].LunID,
+						lunid);
+#endif /* CCISS_DEBUG */
+			if (h->drv[j].LunID == lunid)
+			{
+				lunID_found = 1;
+				break;
+			}
+			
+		}
+		if( lunID_found == 1)
+			continue;
+		else
+		{	/* It is the new lun we have been looking for */
+#ifdef CCISS_DEBUG
+			printk("new lun found at %d\n", i);
+#endif /* CCISS_DEBUG */
+			new_lun_index = i;
+			new_lun_found = 1;
+			break;	
+		}
+	 }
+	 if (!new_lun_found)
+	 {
+		printk(KERN_WARNING "cciss:  New Logical Volume not found\n");
+		return -1;
+	 }
+	 /* Now find the free index 	*/
+	for(i=0; i <CISS_MAX_LUN; i++)
+	{
+#ifdef CCISS_DEBUG
+		printk("Checking Index %d\n", i);
+#endif /* CCISS_DEBUG */
+		if(hba[ctlr]->drv[i].LunID == 0)
+		{
+#ifdef CCISS_DEBUG
+			printk("free index found at %d\n", i);
+#endif /* CCISS_DEBUG */
+			free_index_found = 1;
+			free_index = i;
+			break;
+		}
+	}
+	if (!free_index_found)
+	{
+		printk(KERN_WARNING "cciss: unable to find free slot for disk\n");
+                return -1;
+         }
+
+	logvol = free_index;
+	hba[ctlr]->drv[logvol].LunID = lunid;
+		/* there could be gaps in lun numbers, track hightest */
+	if(hba[ctlr]->highest_lun < lunid)
+		hba[ctlr]->highest_lun = logvol;
+		
+	memset(size_buff, 0, sizeof(ReadCapdata_struct));
+	return_code = sendcmd_withirq(CCISS_READ_CAPACITY, ctlr, size_buff,
+		sizeof( ReadCapdata_struct), 1, logvol, 0 );
+	if (return_code == IO_OK)
+	{
+		total_size = (0xff & 
+			(unsigned int)(size_buff->total_size[0])) << 24;
+		total_size |= (0xff & 
+				(unsigned int)(size_buff->total_size[1])) << 16;
+		total_size |= (0xff & 
+				(unsigned int)(size_buff->total_size[2])) << 8;
+		total_size |= (0xff & (unsigned int)
+				(size_buff->total_size[3])); 
+		total_size++; // command returns highest block address
+
+		block_size = (0xff & 
+				(unsigned int)(size_buff->block_size[0])) << 24;
+               	block_size |= (0xff & 
+				(unsigned int)(size_buff->block_size[1])) << 16;
+               	block_size |= (0xff & 
+				(unsigned int)(size_buff->block_size[2])) << 8;
+               	block_size |= (0xff & 
+				(unsigned int)(size_buff->block_size[3]));
+	} else /* read capacity command failed */ 
+	{
+			printk(KERN_WARNING "cciss: read capacity failed\n");
+			total_size = 0;
+			block_size = BLOCK_SIZE;
+	}	
+	printk(KERN_INFO "      blocks= %d block_size= %d\n", 
+					total_size, block_size);
+	/* Execute the command to read the disk geometry */
+	memset(inq_buff, 0, sizeof(InquiryData_struct));
+	return_code = sendcmd_withirq(CISS_INQUIRY, ctlr, inq_buff,
+                	sizeof(InquiryData_struct), 1, logvol ,0xC1 );
+	if (return_code == IO_OK)
+		{
+			if(inq_buff->data_byte[8] == 0xFF)
+			{
+			   printk(KERN_WARNING "cciss: reading geometry failed, "
+				"volume does not support reading geometry\n");
+
+                           hba[ctlr]->drv[logvol].block_size = block_size;
+                           hba[ctlr]->drv[logvol].nr_blocks = total_size;
+                           hba[ctlr]->drv[logvol].heads = 255;
+                           hba[ctlr]->drv[logvol].sectors = 32; // Sectors per track
+                           hba[ctlr]->drv[logvol].cylinders = total_size / 255 / 32;
+                	} else
+			{
+
+		 	   hba[ctlr]->drv[logvol].block_size = block_size;
+                           hba[ctlr]->drv[logvol].nr_blocks = total_size;
+                           hba[ctlr]->drv[logvol].heads = 
+					inq_buff->data_byte[6]; 
+                           hba[ctlr]->drv[logvol].sectors = 
+					inq_buff->data_byte[7]; 
+			   hba[ctlr]->drv[logvol].cylinders = 
+					(inq_buff->data_byte[4] & 0xff) << 8;
+			   hba[ctlr]->drv[logvol].cylinders += 
+                                        inq_buff->data_byte[5];
+			}
+		}
+		else /* Get geometry failed */
+		{
+
+			printk(KERN_WARNING "cciss: reading geometry failed, "
+				"continuing with default geometry\n"); 
+
+			hba[ctlr]->drv[logvol].block_size = block_size;
+			hba[ctlr]->drv[logvol].nr_blocks = total_size;
+			hba[ctlr]->drv[logvol].heads = 255;
+			hba[ctlr]->drv[logvol].sectors = 32; // Sectors per track 
+			hba[ctlr]->drv[logvol].cylinders = total_size / 255 / 32;
+		}
+		printk(KERN_INFO "      heads= %d, sectors= %d, cylinders= %d\n\n",
+			hba[ctlr]->drv[logvol].heads, 
+			hba[ctlr]->drv[logvol].sectors,
+			hba[ctlr]->drv[logvol].cylinders);
+	hba[ctlr]->drv[logvol].usage_count = 0;
+	max_p = 1 << gdev->minor_shift;
+        start = logvol<< gdev->minor_shift;
+
+        for(i=max_p-1; i>=0; i--) {
+                int minor = start+i;
+		kdev_t kdev = mk_kdev(MAJOR_NR + ctlr, minor);
+                invalidate_device(kdev, 1);
+                gdev->part[minor].start_sect = 0;
+                gdev->part[minor].nr_sects = 0;
+
+                /* reset the blocksize so we can read the partition table */
+                blksize_size[MAJOR_NR+ctlr][minor] = 1024;
+        }
+
+	++hba[ctlr]->num_luns;
+	gdev->nr_real = hba[ctlr]->highest_lun + 1;
+	/* setup partitions per disk */
+	grok_partitions(dev, hba[ctlr]->drv[logvol].nr_blocks);
+	
+	kfree(ld_buff);
+	kfree(size_buff);
+	kfree(inq_buff);
+	return (logvol);
+}
 /*
  *   Wait polling for a command to complete.
  *   The memory mapped FIFO is polled for the completion.
@@ -959,6 +1489,15 @@
                         c->Request.Timeout = 0; // Don't time out
                         c->Request.CDB[0] = CCISS_READ_CAPACITY;
 		break;
+		case CCISS_CACHE_FLUSH:
+			c->Request.CDBLen = 12;
+                        c->Request.Type.Type =  TYPE_CMD; // It is a command.
+                        c->Request.Type.Attribute = ATTR_SIMPLE;
+                        c->Request.Type.Direction = XFER_WRITE; // No data
+                        c->Request.Timeout = 0; // Don't time out
+                        c->Request.CDB[0] = BMIC_WRITE;  // BMIC Passthru
+                        c->Request.CDB[6] = BMIC_CACHE_FLUSH;
+		break;
 		default:
 			printk(KERN_WARNING
 				"cciss:  Unknown Command 0x%c sent attempted\n",
@@ -1169,17 +1708,32 @@
 	{ /* an error has occurred */ 
 		switch(cmd->err_info->CommandStatus)
 		{
+			unsigned char sense_key;
 			case CMD_TARGET_STATUS:
-				printk(KERN_WARNING "cciss: cmd %p has "
-					" completed with errors\n", cmd);
-				if( cmd->err_info->ScsiStatus)
-                		{
-                    			printk(KERN_WARNING "cciss: cmd %p "
-					"has SCSI Status = %x\n",
-                        			cmd,  
-						cmd->err_info->ScsiStatus);
-                		}
-
+				status = 0;
+			
+				if( cmd->err_info->ScsiStatus == 0x02)
+				{
+					printk(KERN_WARNING "cciss: cmd %p "
+                                        	"has CHECK CONDITION "
+						" byte 2 = 0x%x\n", cmd,
+						cmd->err_info->SenseInfo[2]
+					);
+					/* check the sense key */
+					sense_key = 0xf & 
+						cmd->err_info->SenseInfo[2];
+					/* no status or recovered error */
+					if((sense_key == 0x0) ||
+					    (sense_key == 0x1))
+					{
+							status = 1;
+					}
+				} else
+				{
+					printk(KERN_WARNING "cciss: cmd %p "
+                                                "has SCSI Status 0x%x\n",
+						cmd, cmd->err_info->ScsiStatus);
+				}
 			break;
 			case CMD_DATA_UNDERRUN:
 				printk(KERN_WARNING "cciss: cmd %p has"
@@ -1460,6 +2014,15 @@
 }
 #endif /* CCISS_DEBUG */ 
 
+static void release_io_mem(ctlr_info_t *c)
+{
+	/* if IO mem was not protected do nothing */
+	if( c->io_mem_addr == 0)
+		return;
+	release_region(c->io_mem_addr, c->io_mem_length);
+	c->io_mem_addr = 0;
+	c->io_mem_length = 0;
+}
 static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
 {
 	ushort vendor_id, device_id, command;
@@ -1489,17 +2052,49 @@
 		printk(KERN_ERR "cciss:  Unable to set DMA mask\n");
 		return(-1);
 	}
-	
+
 	(void) pci_read_config_word(pdev, PCI_COMMAND,&command);
 	(void) pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
 	(void) pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE,
 						&cache_line_size);
 	(void) pci_read_config_byte(pdev, PCI_LATENCY_TIMER,
 						&latency_timer);
-
 	(void) pci_read_config_dword(pdev, PCI_SUBSYSTEM_VENDOR_ID, 
 						&board_id);
 
+	/* check to see if controller has been disabled */
+	if(!(command & 0x02))
+	{
+		printk(KERN_WARNING "cciss: controller appears to be disabled\n");
+		return(-1);
+	}
+
+	/* search for our IO range so we can protect it */
+	for(i=0; i<6; i++)
+	{
+		/* is this an IO range */ 
+		if( pdev->resource[i].flags & 0x01 )
+		{
+			c->io_mem_addr = pdev->resource[i].start;
+			c->io_mem_length = pdev->resource[i].end -
+				pdev->resource[i].start +1; 
+#ifdef CCISS_DEBUG
+			printk("IO value found base_addr[%d] %lx %lx\n", i,
+				c->io_mem_addr, c->io_mem_length);
+#endif /* CCISS_DEBUG */
+			/* register the IO range */ 
+			if(!request_region( c->io_mem_addr,
+                                        c->io_mem_length, "cciss"))
+			{
+				printk(KERN_WARNING "cciss I/O memory range already in use addr=%lx length=%ld\n",
+				c->io_mem_addr, c->io_mem_length);
+				c->io_mem_addr= 0;
+				c->io_mem_length = 0;
+			} 
+			break;
+		}
+	}
+
 #ifdef CCISS_DEBUG
 	printk("vendor_id = %x\n", vendor_id);
 	printk("device_id = %x\n", device_id);
@@ -1520,7 +2115,7 @@
          *   table
 	 */
 
-	c->paddr = addr[0] & 0xfffffff0; /* remove the addressing mode bits */
+	c->paddr = addr[0] ; /* addressing mode bits already removed */
 #ifdef CCISS_DEBUG
 	printk("address 0 = %x\n", c->paddr);
 #endif /* CCISS_DEBUG */ 
@@ -1617,7 +2212,7 @@
 	int return_code;
 	int i;
 	int listlength = 0;
-	int lunid = 0;
+	__u32 lunid = 0;
 	int block_size;
 	int total_size; 
 
@@ -1689,14 +2284,19 @@
 		ld_buff->LUNListLength[1], ld_buff->LUNListLength[2],
 		ld_buff->LUNListLength[3],  hba[cntl_num]->num_luns);
 #endif /* CCISS_DEBUG */
-	for(i=0; i<  hba[cntl_num]->num_luns ; i++)
+
+	hba[cntl_num]->highest_lun = hba[cntl_num]->num_luns-1;
+	for(i=0; i<  hba[cntl_num]->num_luns; i++)
 	{
+
 	  	lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) << 24;
         	lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) << 16;
         	lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) << 8;
         	lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]);
+		
 		hba[cntl_num]->drv[i].LunID = lunid;
 
+
 #ifdef CCISS_DEBUG
 	  	printk(KERN_DEBUG "LUN[%d]:  %x %x %x %x = %x\n", i, 
 		ld_buff->LUN[i][0], ld_buff->LUN[i][1],ld_buff->LUN[i][2], 
@@ -1729,7 +2329,8 @@
 		} else /* read capacity command failed */ 
 		{
 			printk(KERN_WARNING "cciss: read capacity failed\n");
-			total_size = block_size = 0; 
+			total_size = 0;
+			block_size = BLOCK_SIZE;
 		}	
 		printk(KERN_INFO "      blocks= %d block_size= %d\n", 
 					total_size, block_size);
@@ -1781,6 +2382,7 @@
 	}
 	kfree(ld_buff);
 	kfree(size_buff);
+	kfree(inq_buff);
 }	
 
 /* Function to find the first free pointer into our hba[] array */
@@ -1834,6 +2436,7 @@
 	memset(hba[i], 0, sizeof(ctlr_info_t));
 	if (cciss_pci_init(hba[i], pdev) != 0)
 	{
+		release_io_mem(hba[i]);
 		free_hba(i);
 		return (-1);
 	}
@@ -1856,6 +2459,7 @@
 	{
 		printk(KERN_ERR "cciss:  Unable to get major number "
 			"%d for %s\n", MAJOR_NR+i, hba[i]->devname);
+		release_io_mem(hba[i]);
 		free_hba(i);
 		return(-1);
 	}
@@ -1867,6 +2471,7 @@
 		printk(KERN_ERR "ciss: Unable to get irq %d for %s\n",
 			hba[i]->intr, hba[i]->devname);
 		unregister_blkdev( MAJOR_NR+i, hba[i]->devname);
+		release_io_mem(hba[i]);
 		free_hba(i);
 		return(-1);
 	}
@@ -1895,6 +2500,7 @@
 				hba[i]->errinfo_pool_dhandle);
                 free_irq(hba[i]->intr, hba[i]);
                 unregister_blkdev(MAJOR_NR+i, hba[i]->devname);
+		release_io_mem(hba[i]);
 		free_hba(i);
                 printk( KERN_ERR "cciss: out of memory");
 		return(-1);
@@ -1944,7 +2550,7 @@
 	hba[i]->gendisk.minor_shift = NWD_SHIFT;
 	hba[i]->gendisk.part = hba[i]->hd;
 	hba[i]->gendisk.sizes = hba[i]->sizes;
-	hba[i]->gendisk.nr_real = hba[i]->num_luns;
+	hba[i]->gendisk.nr_real = hba[i]->highest_lun+1;  
 
 	/* Get on the disk list */ 
 	add_gendisk(&(hba[i]->gendisk));
@@ -1965,6 +2571,8 @@
 {
 	ctlr_info_t *tmp_ptr;
 	int i;
+	char flush_buf[4];
+	int return_code; 
 
 	if (pci_get_drvdata(pdev) == NULL)
 	{
@@ -1979,8 +2587,16 @@
 			"already be removed \n");
 		return;
 	}
-	/* Turn board interrupts off */
-	hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF);
+	/* Turn board interrupts off  and send the flush cache command */
+	/* sendcmd will turn off interrupt, and send the flush...
+	* To write all data in the battery backed cache to disks */
+	memset(flush_buf, 0, 4);
+	return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4, 0, 0, 0, NULL);
+	if(return_code != IO_OK)
+	{
+		printk(KERN_WARNING "Error Flushing cache on controller %d\n", 
+			i);
+	}
 	free_irq(hba[i]->intr, hba[i]);
 	pci_set_drvdata(pdev, NULL);
 	iounmap((void*)hba[i]->vaddr);
@@ -1996,6 +2612,7 @@
 	pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof( ErrorInfo_struct),
 		hba[i]->errinfo_pool, hba[i]->errinfo_pool_dhandle);
 	kfree(hba[i]->cmd_pool_bits);
+ 	release_io_mem(hba[i]);
 	free_hba(i);
 }	
 
diff -u --recursive --new-file v2.5.2/linux/drivers/block/cciss.h linux/drivers/block/cciss.h
--- v2.5.2/linux/drivers/block/cciss.h	Mon Jan 14 18:25:09 2002
+++ linux/drivers/block/cciss.h	Fri Jan 18 14:05:55 2002
@@ -46,6 +46,8 @@
 	__u32	board_id;
 	ulong   vaddr;
 	__u32	paddr;	
+	unsigned long io_mem_addr;
+	unsigned long io_mem_length;
 	CfgTable_struct *cfgtable;
 	int	intr;
 
@@ -53,6 +55,7 @@
 	int	commands_outstanding;
 	int 	max_outstanding; /* Debug */ 
 	int	num_luns;
+	int 	highest_lun;
 	int	usage_count;  /* number of opens all all minor devices */
 
 	// information about each logical volume
diff -u --recursive --new-file v2.5.2/linux/drivers/block/cciss_cmd.h linux/drivers/block/cciss_cmd.h
--- v2.5.2/linux/drivers/block/cciss_cmd.h	Mon Jan 14 18:25:09 2002
+++ linux/drivers/block/cciss_cmd.h	Fri Jan 18 14:05:55 2002
@@ -124,6 +124,12 @@
  #define CCISS_READ   0x28    // Read(10)
  #define CCISS_WRITE  0x2a    // Write(10)
 
+// BMIC commands 
+#define BMIC_READ 0x26
+#define BMIC_WRITE 0x27
+#define BMIC_CACHE_FLUSH 0xc2
+#define CCISS_CACHE_FLUSH 0x01	//C2 was already being used by CCISS
+
 //Command List Structure
 typedef union _SCSI3Addr_struct {
    struct {
diff -u --recursive --new-file v2.5.2/linux/drivers/block/cciss_scsi.c linux/drivers/block/cciss_scsi.c
--- v2.5.2/linux/drivers/block/cciss_scsi.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/block/cciss_scsi.c	Tue Jan 15 10:52:11 2002
@@ -209,13 +209,11 @@
 	stk = &sa->cmd_stack; 
 	size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * CMD_STACK_SIZE;
 
-	// We use NULL as first arg to pci_alloc_consistent so we can be
-	// sure that we get addresses that will fit through the 32 bit
-	// command register, (our DMA mask says we can do 64 bit DMA, which
-	// we, can, just not for commands.)
+	// pci_alloc_consistent guarentees 32-bit DMA address will
+	// be used
 
 	stk->pool = (struct cciss_scsi_cmd_stack_elem_t *)
-		pci_alloc_consistent(NULL, size, &stk->cmd_pool_handle);
+		pci_alloc_consistent(hba[ctlr]->pdev, size, &stk->cmd_pool_handle);
 
 	if (stk->pool == NULL) {
 		printk("stk->pool is null\n");
@@ -249,8 +247,7 @@
 	}
 	size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * CMD_STACK_SIZE;
 
-	// About NULL, see note above near pci_alloc_consistent	
-	pci_free_consistent(NULL, size, stk->pool, stk->cmd_pool_handle);
+	pci_free_consistent(hba[ctlr]->pdev, size, stk->pool, stk->cmd_pool_handle);
 	stk->pool = NULL;
 }
 
diff -u --recursive --new-file v2.5.2/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v2.5.2/linux/drivers/block/ll_rw_blk.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/block/ll_rw_blk.c	Sat Jan 19 16:49:38 2002
@@ -186,7 +186,8 @@
 	 * full 4GB zone, so we have to resort to low memory for any bounces.
 	 * ISA has its own < 16MB zone.
 	 */
-	if (dma_addr == BLK_BOUNCE_ISA) {
+	if (bounce_pfn < blk_max_low_pfn) {
+		BUG_ON(dma_addr < BLK_BOUNCE_ISA);
 		init_emergency_isa_pool();
 		q->bounce_gfp = GFP_NOIO | GFP_DMA;
 	} else
@@ -302,8 +303,8 @@
 static char *rq_flags[] = { "REQ_RW", "REQ_RW_AHEAD", "REQ_BARRIER",
 			   "REQ_CMD", "REQ_NOMERGE", "REQ_STARTED",
 			   "REQ_DONTPREP", "REQ_DRIVE_CMD", "REQ_DRIVE_TASK",
-			   "REQ_PC", "REQ_BLOCK_PC", "REQ_SENSE",
-			   "REQ_SPECIAL" };
+			   "REQ_DRIVE_ACB", "REQ_PC", "REQ_BLOCK_PC",
+			   "REQ_SENSE", "REQ_SPECIAL" };
 
 void blk_dump_rq_flags(struct request *rq, char *msg)
 {
diff -u --recursive --new-file v2.5.2/linux/drivers/block/loop.c linux/drivers/block/loop.c
--- v2.5.2/linux/drivers/block/loop.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/block/loop.c	Mon Jan 14 21:49:42 2002
@@ -534,7 +534,6 @@
 	struct bio *bio;
 
 	daemonize();
-	exit_files(current);
 
 	sprintf(current->comm, "loop%d", lo->lo_number);
 
diff -u --recursive --new-file v2.5.2/linux/drivers/block/paride/pf.c linux/drivers/block/paride/pf.c
--- v2.5.2/linux/drivers/block/paride/pf.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/block/paride/pf.c	Tue Jan 15 10:58:04 2002
@@ -684,7 +684,8 @@
 	for (k=0;k<len;k++) 
 	   if((buf[k+offs]!=0x20)||(buf[k+offs]!=l))
 		l=targ[j++]=buf[k+offs];
-	if (l==0x20) j--; targ[j]=0;
+	if (l==0x20) j--;
+	targ[j]=0;
 }
 
 static int xl( char *buf, int offs )
diff -u --recursive --new-file v2.5.2/linux/drivers/block/paride/pg.c linux/drivers/block/paride/pg.c
--- v2.5.2/linux/drivers/block/paride/pg.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/block/paride/pg.c	Tue Jan 15 10:58:04 2002
@@ -491,7 +491,8 @@
 	for (k=0;k<len;k++) 
 	   if((buf[k+offs]!=0x20)||(buf[k+offs]!=l))
 		l=targ[j++]=buf[k+offs];
-	if (l==0x20) j--; targ[j]=0;
+	if (l==0x20) j--;
+	targ[j]=0;
 }
 
 static int pg_identify( int unit, int log )
diff -u --recursive --new-file v2.5.2/linux/drivers/block/paride/pseudo.h linux/drivers/block/paride/pseudo.h
--- v2.5.2/linux/drivers/block/paride/pseudo.h	Sun Feb  4 10:05:29 2001
+++ linux/drivers/block/paride/pseudo.h	Tue Jan 15 10:58:04 2002
@@ -102,7 +102,7 @@
 		spin_unlock_irqrestore(&ps_spinlock,flags);
 		return;
 	}
-        if (!ps_ready || ps_ready() || (jiffies >= ps_timeout)) {
+        if (!ps_ready || ps_ready() || time_after_eq(jiffies, ps_timeout)) {
                 ps_continuation = NULL;
         	spin_unlock_irqrestore(&ps_spinlock,flags);
                 con();
@@ -131,7 +131,7 @@
 	        spin_unlock_irqrestore(&ps_spinlock,flags);
 		return;
 	}
-        if (!ps_ready || ps_ready() || (jiffies >= ps_timeout)) {
+        if (!ps_ready || ps_ready() || time_after_eq(jiffies, ps_timeout)) {
                 ps_continuation = NULL;
 	        spin_unlock_irqrestore(&ps_spinlock,flags);
                 con();
diff -u --recursive --new-file v2.5.2/linux/drivers/block/paride/pt.c linux/drivers/block/paride/pt.c
--- v2.5.2/linux/drivers/block/paride/pt.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/block/paride/pt.c	Tue Jan 15 10:58:04 2002
@@ -577,7 +577,8 @@
 	for (k=0;k<len;k++) 
 	   if((buf[k+offs]!=0x20)||(buf[k+offs]!=l))
 		l=targ[j++]=buf[k+offs];
-	if (l==0x20) j--; targ[j]=0;
+	if (l==0x20) j--;
+	targ[j]=0;
 }
 
 static int xn( char *buf, int offs, int size )
diff -u --recursive --new-file v2.5.2/linux/drivers/char/agp/agpgart_fe.c linux/drivers/char/agp/agpgart_fe.c
--- v2.5.2/linux/drivers/char/agp/agpgart_fe.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/char/agp/agpgart_fe.c	Tue Jan 15 10:56:35 2002
@@ -638,7 +638,7 @@
 			AGP_UNLOCK();
 			return -EINVAL;
 		}
-		if (remap_page_range(vma->vm_start,
+		if (remap_page_range(vma, vma->vm_start,
 				     (kerninfo.aper_base + offset),
 				     size, vma->vm_page_prot)) {
 			AGP_UNLOCK();
@@ -652,7 +652,7 @@
 			AGP_UNLOCK();
 			return -EINVAL;
 		}
-		if (remap_page_range(vma->vm_start, kerninfo.aper_base,
+		if (remap_page_range(vma, vma->vm_start, kerninfo.aper_base,
 				     size, vma->vm_page_prot)) {
 			AGP_UNLOCK();
 			return -EAGAIN;
diff -u --recursive --new-file v2.5.2/linux/drivers/char/drm/drm_vm.h linux/drivers/char/drm/drm_vm.h
--- v2.5.2/linux/drivers/char/drm/drm_vm.h	Thu Nov 22 11:46:37 2001
+++ linux/drivers/char/drm/drm_vm.h	Sat Jan 19 14:30:34 2002
@@ -532,12 +532,12 @@
 		}
 		offset = DRIVER_GET_REG_OFS();
 #ifdef __sparc__
-		if (io_remap_page_range(vma->vm_start,
+		if (io_remap_page_range(vma, vma->vm_start,
 					VM_OFFSET(vma) + offset,
 					vma->vm_end - vma->vm_start,
 					vma->vm_page_prot, 0))
 #else
-		if (remap_page_range(vma->vm_start,
+		if (remap_page_range(vma, vma->vm_start,
 				     VM_OFFSET(vma) + offset,
 				     vma->vm_end - vma->vm_start,
 				     vma->vm_page_prot))
diff -u --recursive --new-file v2.5.2/linux/drivers/char/drm/i810_dma.c linux/drivers/char/drm/i810_dma.c
--- v2.5.2/linux/drivers/char/drm/i810_dma.c	Wed Aug  8 09:42:15 2001
+++ linux/drivers/char/drm/i810_dma.c	Tue Jan 15 10:56:35 2002
@@ -163,7 +163,7 @@
    	buf_priv->currently_mapped = I810_BUF_MAPPED;
 	unlock_kernel();
 
-	if (remap_page_range(vma->vm_start,
+	if (remap_page_range(vma, vma->vm_start,
 			     VM_OFFSET(vma),
 			     vma->vm_end - vma->vm_start,
 			     vma->vm_page_prot)) return -EAGAIN;
diff -u --recursive --new-file v2.5.2/linux/drivers/char/ftape/lowlevel/ftape-ctl.c linux/drivers/char/ftape/lowlevel/ftape-ctl.c
--- v2.5.2/linux/drivers/char/ftape/lowlevel/ftape-ctl.c	Tue Nov  7 11:09:19 2000
+++ linux/drivers/char/ftape/lowlevel/ftape-ctl.c	Tue Jan 15 10:56:35 2002
@@ -731,7 +731,7 @@
 		ftape_reset_buffer();
 	}
 	for (i = 0; i < num_buffers; i++) {
-		TRACE_CATCH(remap_page_range(vma->vm_start +
+		TRACE_CATCH(remap_page_range(vma, vma->vm_start +
 					     i * FT_BUFF_SIZE,
 					     virt_to_phys(ft_buffer[i]->address),
 					     FT_BUFF_SIZE,
diff -u --recursive --new-file v2.5.2/linux/drivers/char/lp.c linux/drivers/char/lp.c
--- v2.5.2/linux/drivers/char/lp.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/char/lp.c	Tue Jan 15 13:53:51 2002
@@ -367,7 +367,7 @@
 			  = lp_negotiate (port, 
 					  lp_table[minor].best_mode);
 
-		} else if (current->need_resched)
+		} else if (need_resched())
 			schedule ();
 
 		if (count) {
diff -u --recursive --new-file v2.5.2/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v2.5.2/linux/drivers/char/mem.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/char/mem.c	Tue Jan 15 13:53:51 2002
@@ -203,7 +203,7 @@
 	if (offset >= __pa(high_memory) || (file->f_flags & O_SYNC))
 		vma->vm_flags |= VM_IO;
 
-	if (remap_page_range(vma->vm_start, offset, vma->vm_end-vma->vm_start,
+	if (remap_page_range(vma, vma->vm_start, offset, vma->vm_end-vma->vm_start,
 			     vma->vm_page_prot))
 		return -EAGAIN;
 	return 0;
@@ -364,8 +364,8 @@
 		if (count > size)
 			count = size;
 
-		zap_page_range(mm, addr, count);
-        	zeromap_page_range(addr, count, PAGE_COPY);
+		zap_page_range(vma, addr, count);
+        	zeromap_page_range(vma, addr, count, PAGE_COPY);
 
 		size -= count;
 		buf += count;
@@ -381,8 +381,7 @@
 		unsigned long unwritten = clear_user(buf, PAGE_SIZE);
 		if (unwritten)
 			return size + unwritten - PAGE_SIZE;
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 		buf += PAGE_SIZE;
 		size -= PAGE_SIZE;
 	} while (size);
@@ -435,7 +434,7 @@
 {
 	if (vma->vm_flags & VM_SHARED)
 		return shmem_zero_setup(vma);
-	if (zeromap_page_range(vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot))
+	if (zeromap_page_range(vma, vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot))
 		return -EAGAIN;
 	return 0;
 }
diff -u --recursive --new-file v2.5.2/linux/drivers/char/mwave/3780i.c linux/drivers/char/mwave/3780i.c
--- v2.5.2/linux/drivers/char/mwave/3780i.c	Sun Sep 30 12:26:05 2001
+++ linux/drivers/char/mwave/3780i.c	Tue Jan 15 13:53:51 2002
@@ -68,11 +68,9 @@
 
 static void PaceMsaAccess(unsigned short usDspBaseIO)
 {
-	if(current->need_resched)
-		schedule();
+	cond_resched();
 	udelay(100);
-	if(current->need_resched)
-		schedule();
+	cond_resched();
 }
 
 unsigned short dsp3780I_ReadMsaCfg(unsigned short usDspBaseIO,
diff -u --recursive --new-file v2.5.2/linux/drivers/char/ppdev.c linux/drivers/char/ppdev.c
--- v2.5.2/linux/drivers/char/ppdev.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/char/ppdev.c	Tue Jan 15 13:53:51 2002
@@ -170,9 +170,7 @@
 			break;
 		}
 
-		if (current->need_resched) {
-			schedule ();
-		}
+		cond_resched();
 	}
 
 	kfree (kbuffer);
@@ -242,9 +240,7 @@
 			break;
 		}
 
-		if (current->need_resched) {
-			schedule ();
-		}
+		cond_resched();
 	}
 
 	kfree (kbuffer);
diff -u --recursive --new-file v2.5.2/linux/drivers/char/random.c linux/drivers/char/random.c
--- v2.5.2/linux/drivers/char/random.c	Fri Nov  9 14:01:21 2001
+++ linux/drivers/char/random.c	Tue Jan 15 13:53:51 2002
@@ -1313,7 +1313,7 @@
 		/*
 		 * Check if we need to break out or reschedule....
 		 */
-		if ((flags & EXTRACT_ENTROPY_USER) && current->need_resched) {
+		if ((flags & EXTRACT_ENTROPY_USER) && need_resched()) {
 			if (signal_pending(current)) {
 				if (ret == 0)
 					ret = -ERESTARTSYS;
diff -u --recursive --new-file v2.5.2/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v2.5.2/linux/drivers/char/tty_io.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/char/tty_io.c	Tue Jan 15 13:53:51 2002
@@ -712,8 +712,7 @@
 			ret = -ERESTARTSYS;
 			if (signal_pending(current))
 				break;
-			if (current->need_resched)
-				schedule();
+			cond_resched();
 		}
 	}
 	if (written) {
diff -u --recursive --new-file v2.5.2/linux/drivers/fc4/fc.c linux/drivers/fc4/fc.c
--- v2.5.2/linux/drivers/fc4/fc.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/fc4/fc.c	Tue Jan 15 10:52:11 2002
@@ -769,10 +769,10 @@
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+	spin_lock_irqsave(SCpnt->host->host_lock, flags);
 	if (FCP_CMND(SCpnt)->done)
 		FCP_CMND(SCpnt)->done(SCpnt);
-	spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+	spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
 }
 
 static int fcp_scsi_queue_it(fc_channel *fc, Scsi_Cmnd *SCpnt, fcp_cmnd *fcmd, int prepare)
@@ -920,9 +920,9 @@
 		unsigned long flags;
 
 		SCpnt->result = DID_ABORT;
-		spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+		spin_lock_irqsave(SCpnt->host->host_lock, flags);
 		fcmd->done(SCpnt);
-		spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+		spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
 		printk("FC: soft abort\n");
 		return SUCCESS;
 	} else {
diff -u --recursive --new-file v2.5.2/linux/drivers/hotplug/cpqphp_core.c linux/drivers/hotplug/cpqphp_core.c
--- v2.5.2/linux/drivers/hotplug/cpqphp_core.c	Fri Nov  9 14:01:21 2001
+++ linux/drivers/hotplug/cpqphp_core.c	Thu Jan 17 14:06:53 2002
@@ -404,6 +404,10 @@
 		result = pci_hp_register (new_slot->hotplug_slot);
 		if (result) {
 			err ("pci_hp_register failed with error %d\n", result);
+			kfree (new_slot->hotplug_slot->info);
+			kfree (new_slot->hotplug_slot->name);
+			kfree (new_slot->hotplug_slot);
+			kfree (new_slot);
 			return result;
 		}
 		
@@ -429,6 +433,8 @@
 	while (old_slot) {
 		next_slot = old_slot->next;
 		pci_hp_deregister (old_slot->hotplug_slot);
+		kfree(old_slot->hotplug_slot->info);
+		kfree(old_slot->hotplug_slot->name);
 		kfree(old_slot->hotplug_slot);
 		kfree(old_slot);
 		old_slot = next_slot;
diff -u --recursive --new-file v2.5.2/linux/drivers/i2c/i2c-algo-bit.c linux/drivers/i2c/i2c-algo-bit.c
--- v2.5.2/linux/drivers/i2c/i2c-algo-bit.c	Thu Oct 11 08:05:47 2001
+++ linux/drivers/i2c/i2c-algo-bit.c	Tue Jan 15 13:53:51 2002
@@ -50,7 +50,7 @@
 /* might not like this, as they have an internal timeout of some mils	*/
 /*
 #define SLO_IO      jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\
-                        if (need_resched) schedule();
+                        cond_resched();
 */
 
 
@@ -120,8 +120,7 @@
 		if (start+adap->timeout <= jiffies) {
 			return -ETIMEDOUT;
 		}
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 	}
 	DEBSTAT(printk("needed %ld jiffies\n", jiffies-start));
 #ifdef SLO_IO
diff -u --recursive --new-file v2.5.2/linux/drivers/i2c/i2c-algo-ite.c linux/drivers/i2c/i2c-algo-ite.c
--- v2.5.2/linux/drivers/i2c/i2c-algo-ite.c	Thu Oct 11 08:05:47 2001
+++ linux/drivers/i2c/i2c-algo-ite.c	Tue Jan 15 13:53:51 2002
@@ -67,7 +67,7 @@
 /* might not like this, as they have an internal timeout of some mils	*/
 /*
 #define SLO_IO      jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\
-                        if (need_resched) schedule();
+                        cond_resched();
 */
 
 
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/Config.in linux/drivers/ide/Config.in
--- v2.5.2/linux/drivers/ide/Config.in	Mon Oct  8 11:40:13 2001
+++ linux/drivers/ide/Config.in	Tue Jan 15 11:27:30 2002
@@ -14,6 +14,7 @@
 
    dep_tristate '  Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE
    dep_mbool '    Use multi-mode by default' CONFIG_IDEDISK_MULTI_MODE $CONFIG_BLK_DEV_IDEDISK
+   dep_mbool '    Auto-Geometry Resizing support' CONFIG_IDEDISK_STROKE $CONFIG_BLK_DEV_IDEDISK
 
    define_bool CONFIG_BLK_DEV_IDEDISK_VENDOR n
    dep_mbool '    Fujitsu Vendor Specific' CONFIG_BLK_DEV_IDEDISK_FUJITSU $CONFIG_BLK_DEV_IDEDISK_VENDOR
@@ -32,6 +33,8 @@
    dep_tristate '  Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE
    dep_tristate '  SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE $CONFIG_SCSI
 
+   bool '  IDE Taskfile Access' CONFIG_IDE_TASK_IOCTL
+
    comment 'IDE chipset support/bugfixes'
    if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
       dep_bool '  CMD640 chipset bugfix/support' CONFIG_BLK_DEV_CMD640 $CONFIG_X86
@@ -43,14 +46,17 @@
 	 if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then
 	    bool '    Sharing PCI IDE interrupts support' CONFIG_IDEPCI_SHARE_IRQ
 	    bool '    Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA_PCI
-#	    bool '    Asynchronous DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI
-	    define_bool CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI
 	    bool '    Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD
+	    dep_bool '      Force enable legacy 2.0.X HOSTS to use DMA' CONFIG_BLK_DEV_IDEDMA_FORCED $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_bool '      Use PCI DMA by default when available' CONFIG_IDEDMA_PCI_AUTO $CONFIG_BLK_DEV_IDEDMA_PCI
+            dep_bool '    Enable DMA only for disks ' CONFIG_IDEDMA_ONLYDISK $CONFIG_IDEDMA_PCI_AUTO
 	    define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_bool '      ATA Work(s) In Progress (EXPERIMENTAL)' CONFIG_IDEDMA_PCI_WIP $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL
-#	    dep_bool '      Attempt to HACK around Chipsets that TIMEOUT (WIP)' CONFIG_BLK_DEV_IDEDMA_TIMEOUT $CONFIG_IDEDMA_PCI_WIP
+	    dep_bool '      Attempt to HACK around Chipsets that TIMEOUT (WIP)' CONFIG_BLK_DEV_IDEDMA_TIMEOUT $CONFIG_IDEDMA_PCI_WIP
 	    dep_bool '      Good-Bad DMA Model-Firmware (WIP)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS $CONFIG_IDEDMA_PCI_WIP
+#	    dep_bool '      Asynchronous DMA support (WIP) (EXPERIMENTAL)' CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_IDEDMA_PCI_WIP
+	    define_bool CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI
+#	    dep_bool '      Tag Command Queue DMA support (WIP) (EXPERIMENTAL)' CONFIG_BLK_DEV_IDEDMA_TCQ $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_IDEDMA_PCI_WIP
 
 	    dep_bool '    AEC62XX chipset support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_mbool '      AEC62XX Tuning support' CONFIG_AEC62XX_TUNING $CONFIG_BLK_DEV_AEC62XX
@@ -74,7 +80,8 @@
 	    fi
 	    dep_bool '    NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_bool '    OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 $CONFIG_EXPERIMENTAL
-	    dep_bool '    PROMISE PDC202{46|62|65|67|68} support' CONFIG_BLK_DEV_PDC202XX $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_mbool '   Pacific Digital A-DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC_ADMA $CONFIG_BLK_DEV_ADMA $CONFIG_IDEDMA_PCI_WIP
+	    dep_bool '    PROMISE PDC202{46|62|65|67|68|69|70} support' CONFIG_BLK_DEV_PDC202XX $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_bool '      Special UDMA Feature' CONFIG_PDC202XX_BURST $CONFIG_BLK_DEV_PDC202XX
 	    dep_bool '      Special FastTrak Feature' CONFIG_PDC202XX_FORCE $CONFIG_BLK_DEV_PDC202XX
 	    dep_bool '    ServerWorks OSB4/CSB5 chipsets support' CONFIG_BLK_DEV_SVWKS $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
@@ -84,8 +91,6 @@
 	    dep_bool '    VIA82CXXX chipset support' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_BLK_DEV_IDEDMA_PCI
          fi
 
-#	 dep_mbool '   Pacific Digital A-DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC_ADMA $CONFIG_BLK_DEV_ADMA $CONFIG_IDEDMA_PCI_WIP
-
 	 if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then
 	    bool '    Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105
 	 fi
@@ -173,6 +178,7 @@
 else
   define_bool CONFIG_DMA_NONPCI n
 fi
+
 if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \
      "$CONFIG_BLK_DEV_AEC62XX" = "y" -o \
      "$CONFIG_BLK_DEV_ALI15X3" = "y" -o \
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/Makefile linux/drivers/ide/Makefile
--- v2.5.2/linux/drivers/ide/Makefile	Tue Oct  9 09:18:37 2001
+++ linux/drivers/ide/Makefile	Tue Jan 15 11:27:30 2002
@@ -10,7 +10,7 @@
 
 O_TARGET := idedriver.o
 
-export-objs		:= ide.o ide-features.o ataraid.o
+export-objs		:= ide-taskfile.o ide.o ide-features.o ide-probe.o ataraid.o
 list-multi		:= ide-mod.o ide-probe-mod.o
 
 obj-y		:=
@@ -24,6 +24,7 @@
 obj-$(CONFIG_BLK_DEV_IDECD)     += ide-cd.o
 obj-$(CONFIG_BLK_DEV_IDETAPE)   += ide-tape.o
 obj-$(CONFIG_BLK_DEV_IDEFLOPPY) += ide-floppy.o
+
 obj-$(CONFIG_BLK_DEV_IT8172)    += it8172.o
 
 ide-obj-$(CONFIG_BLK_DEV_AEC62XX)	+= aec62xx.o
@@ -69,13 +70,13 @@
 
 # The virtualised raid layers MUST come after the ide itself or bad stuff
 # will happen.
-obj-$(CONFIG_BLK_DEV_ATARAID)	+= ataraid.o
+obj-$(CONFIG_BLK_DEV_ATARAID)		+= ataraid.o
 obj-$(CONFIG_BLK_DEV_ATARAID_PDC)	+= pdcraid.o
 obj-$(CONFIG_BLK_DEV_ATARAID_HPT)	+= hptraid.o
 
 ide-obj-$(CONFIG_PROC_FS)		+= ide-proc.o
 
-ide-mod-objs		:= ide.o ide-features.o $(ide-obj-y)
+ide-mod-objs		:= ide-taskfile.o ide.o ide-features.o $(ide-obj-y)
 ide-probe-mod-objs	:= ide-probe.o ide-geometry.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/alim15x3.c linux/drivers/ide/alim15x3.c
--- v2.5.2/linux/drivers/ide/alim15x3.c	Sun Jul 15 16:22:23 2001
+++ linux/drivers/ide/alim15x3.c	Tue Jan 15 11:27:30 2002
@@ -453,7 +453,7 @@
 		}
 		dma_func = ide_dma_off_quietly;
 		if ((id->field_valid & 4) && (m5229_revision >= 0xC2)) {
-			if (id->dma_ultra & 0x002F) {
+			if (id->dma_ultra & 0x003F) {
 				/* Force if Capable UltraDMA */
 				dma_func = config_chipset_for_dma(drive, can_ultra_dma);
 				if ((id->field_valid & 2) &&
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/cmd64x.c linux/drivers/ide/cmd64x.c
--- v2.5.2/linux/drivers/ide/cmd64x.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/cmd64x.c	Tue Jan 15 11:27:30 2002
@@ -86,6 +86,7 @@
 #include <linux/proc_fs.h>
 
 static int cmd64x_get_info(char *, char **, off_t, int);
+static int cmd680_get_info(char *, char **, off_t, int);
 extern int (*cmd64x_display_info)(char *, char **, off_t, int); /* ide-proc.c */
 extern char *ide_media_verbose(ide_drive_t *);
 static struct pci_dev *bmide_dev;
@@ -180,24 +181,21 @@
 	return p-buffer;	/* => must be less than 4k! */
 }
 
-#if 0
-static char * cmd64x_chipset_data (char *buf, struct pci_dev *dev)
-{
-	char *p = buf;
-	p += sprintf(p, "thingy stuff\n");
-	return (char *)p;
-}
-static int __init cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
+static int cmd680_get_info (char *buffer, char **addr, off_t offset, int count)
 {
 	char *p = buffer;
-	p = cmd64x_chipset_data(buffer, bmide_dev);
-	return p-buffer;	/* hoping it is less than 4K... */
+	p += sprintf(p, "\n                                CMD680 Chipset.\n");
+	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
+	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
+	p += sprintf(p, "PIO Mode:       %s                %s               %s                 %s\n",
+		"?", "?", "?", "?");
+	return p-buffer;	/* => must be less than 4k! */
 }
-#endif
 
 #endif	/* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
 
 byte cmd64x_proc = 0;
+byte cmd680_proc = 0;
 
 /*
  * Registers and masks for easy access by drive index:
@@ -345,10 +343,58 @@
 		setup_count, active_count, recovery_count);
 }
 
-static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+static byte cmd680_taskfile_timing (ide_hwif_t *hwif)
 {
-	byte speed= 0x00;
-	byte set_pio= ide_get_best_pio_mode(drive, 4, 5, NULL);
+	struct pci_dev *dev	= hwif->pci_dev;
+	byte addr_mask		= (hwif->channel) ? 0xB2 : 0xA2;
+	unsigned short		timing;
+
+	pci_read_config_word(dev, addr_mask, &timing);
+
+	switch (timing) {
+		case 0x10c1:	return 4;
+		case 0x10c3:	return 3;
+		case 0x1281:	return 2;
+		case 0x2283:	return 1;
+		case 0x328a:
+		default:	return 0;
+	}
+}
+
+static void cmd680_tuneproc (ide_drive_t *drive, byte mode_wanted)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	byte			drive_pci;
+	unsigned short		speedt;
+
+	switch (drive->dn) {
+		case 0: drive_pci = 0xA4; break;
+		case 1: drive_pci = 0xA6; break;
+		case 2: drive_pci = 0xB4; break;
+		case 3: drive_pci = 0xB6; break;
+		default: return;
+        }
+
+	pci_read_config_word(dev, drive_pci, &speedt);
+
+	/* cheat for now and use the docs */
+//	switch(cmd680_taskfile_timing(hwif)) {
+	switch(mode_wanted) {
+		case 4:		speedt = 0x10c1; break;
+		case 3:		speedt = 0x10C3; break;
+		case 2:		speedt = 0x1104; break;
+		case 1:		speedt = 0x2283; break;
+		case 0:
+		default:	speedt = 0x328A; break;
+	}
+	pci_write_config_word(dev, drive_pci, speedt);
+}
+
+static void config_cmd64x_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+	byte speed	= 0x00;
+	byte set_pio	= ide_get_best_pio_mode(drive, 4, 5, NULL);
 
 	cmd64x_tuneproc(drive, set_pio);
 	speed = XFER_PIO_0 + set_pio;
@@ -356,6 +402,41 @@
 		(void) ide_config_drive_speed(drive, speed);
 }
 
+static void config_cmd680_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 unit			= (drive->select.b.unit & 0x01);
+	u8 addr_mask		= (hwif->channel) ? 0x84 : 0x80;
+	u8 speed		= 0x00;
+	u8 mode_pci		= 0x00;
+	u8 channel_timings	= cmd680_taskfile_timing(hwif);
+	u8 set_pio		= ide_get_best_pio_mode(drive, 4, 5, NULL);
+
+	pci_read_config_byte(dev, addr_mask, &mode_pci);
+	mode_pci &= ~((unit) ? 0x30 : 0x03);
+
+	/* WARNING PIO timing mess is going to happen b/w devices, argh */
+	if ((channel_timings != set_pio) && (set_pio > channel_timings))
+		set_pio = channel_timings;
+
+	cmd680_tuneproc(drive, set_pio);
+	speed = XFER_PIO_0 + set_pio;
+	if (set_speed) {
+		(void) ide_config_drive_speed(drive, speed);
+		drive->current_speed = speed;
+	}
+}
+
+static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+        if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_CMD_680) {
+		config_cmd680_chipset_for_pio(drive, set_speed);
+	} else {
+		config_cmd64x_chipset_for_pio(drive, set_speed);
+	}
+}
+
 static int cmd64x_tune_chipset (ide_drive_t *drive, byte speed)
 {
 #ifdef CONFIG_BLK_DEV_IDEDMA
@@ -363,7 +444,7 @@
 	struct pci_dev *dev	= hwif->pci_dev;
 	int err			= 0;
 
-	byte unit		= (drive->select.b.unit & 0x01);
+	u8 unit			= (drive->select.b.unit & 0x01);
 	u8 pciU			= (hwif->channel) ? UDIDETCR1 : UDIDETCR0;
 	u8 pciD			= (hwif->channel) ? BMIDESR1 : BMIDESR0;
 	u8 regU			= 0;
@@ -424,8 +505,123 @@
 	return err;
 }
 
+static int cmd680_tune_chipset (ide_drive_t *drive, byte speed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 addr_mask		= (hwif->channel) ? 0x84 : 0x80;
+	u8 unit			= (drive->select.b.unit & 0x01);
+	u8 dma_pci		= 0;
+	u8 udma_pci		= 0;
+	u8 mode_pci		= 0;
+	u8 scsc			= 0;
+	u16 ultra		= 0;
+	u16 multi		= 0;
+	int err			= 0;
+
+        pci_read_config_byte(dev, addr_mask, &mode_pci);
+	pci_read_config_byte(dev, 0x8A, &scsc);
+
+        switch (drive->dn) {
+		case 0: dma_pci = 0xA8; udma_pci = 0xAC; break;
+		case 1: dma_pci = 0xAA; udma_pci = 0xAE; break;
+		case 2: dma_pci = 0xB8; udma_pci = 0xBC; break;
+		case 3: dma_pci = 0xBA; udma_pci = 0xBE; break;
+		default: return 1;
+	}
+
+	pci_read_config_byte(dev, addr_mask, &mode_pci);
+	mode_pci &= ~((unit) ? 0x30 : 0x03);
+	pci_read_config_word(dev, dma_pci, &multi);
+	pci_read_config_word(dev, udma_pci, &ultra);
+
+	if ((speed == XFER_UDMA_6) && (scsc & 0x30) == 0x00) {
+		pci_write_config_byte(dev, 0x8A, scsc|0x01);
+		pci_read_config_byte(dev, 0x8A, &scsc);
+	}
+
+	switch(speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case XFER_UDMA_6:
+			if ((scsc & 0x30) == 0x00)
+				goto speed_break;
+			multi = 0x10C1;
+			ultra &= ~0x3F;
+			ultra |= 0x01;
+			break;
+speed_break :
+			speed = XFER_UDMA_5;
+		case XFER_UDMA_5:
+			multi = 0x10C1;
+			ultra &= ~0x3F;
+			ultra |= (((scsc & 0x30) == 0x00) ? 0x01 : 0x02);
+			break;
+		case XFER_UDMA_4:
+			multi = 0x10C1;
+			ultra &= ~0x3F;
+			ultra |= (((scsc & 0x30) == 0x00) ? 0x02 : 0x03);
+			break;
+		case XFER_UDMA_3:
+			multi = 0x10C1;
+			ultra &= ~0x3F;
+			ultra |= (((scsc & 0x30) == 0x00) ? 0x04 : 0x05);
+			break;
+		case XFER_UDMA_2:
+			multi = 0x10C1;
+			ultra &= ~0x3F;
+			ultra |= (((scsc & 0x30) == 0x00) ? 0x05 : 0x07);
+			break;
+		case XFER_UDMA_1:
+			multi = 0x10C1;
+			ultra &= ~0x3F;
+			ultra |= (((scsc & 0x30) == 0x00) ? 0x07 : 0x0B);
+			break;
+		case XFER_UDMA_0:
+			multi = 0x10C1;
+			ultra &= ~0x3F;
+			ultra |= (((scsc & 0x30) == 0x00) ? 0x0C : 0x0F);
+			break;
+		case XFER_MW_DMA_2:
+			multi = 0x10C1;
+			break;
+		case XFER_MW_DMA_1:
+			multi = 0x10C2;
+			break;
+		case XFER_MW_DMA_0:
+			multi = 0x2208;
+			break;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+		case XFER_PIO_4:	cmd680_tuneproc(drive, 4); break;
+		case XFER_PIO_3:	cmd680_tuneproc(drive, 3); break;
+		case XFER_PIO_2:	cmd680_tuneproc(drive, 2); break;
+		case XFER_PIO_1:	cmd680_tuneproc(drive, 1); break;
+		case XFER_PIO_0:	cmd680_tuneproc(drive, 0); break;
+		default:
+			return 1;
+	}
+
+	
+	if (speed >= XFER_MW_DMA_0) 
+		config_cmd680_chipset_for_pio(drive, 0);
+
+	if (speed >= XFER_UDMA_0)
+		mode_pci |= ((unit) ? 0x30 : 0x03);
+	else if (speed >= XFER_MW_DMA_0)
+		mode_pci |= ((unit) ? 0x20 : 0x02);
+	else
+		mode_pci |= ((unit) ? 0x10 : 0x01);
+
+	pci_write_config_byte(dev, addr_mask, mode_pci);
+	pci_write_config_word(dev, dma_pci, multi);
+	pci_write_config_word(dev, udma_pci, ultra);
+
+	err = ide_config_drive_speed(drive, speed);
+	drive->current_speed = speed;
+	return err;
+}
+
 #ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
+static int config_cmd64x_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
 {
 	struct hd_driveid *id	= drive->id;
 	ide_hwif_t *hwif	= HWIF(drive);
@@ -510,6 +706,55 @@
 	return rval;
 }
 
+static int config_cmd680_chipset_for_dma (ide_drive_t *drive)
+{
+	struct hd_driveid *id	= drive->id;
+	byte udma_66		= eighty_ninty_three(drive);
+	byte speed		= 0x00;
+	byte set_pio		= 0x00;
+	int rval;
+
+	if ((id->dma_ultra & 0x0040) && (udma_66))	speed = XFER_UDMA_6;
+	else if ((id->dma_ultra & 0x0020) && (udma_66))	speed = XFER_UDMA_5;
+	else if ((id->dma_ultra & 0x0010) && (udma_66))	speed = XFER_UDMA_4;
+	else if ((id->dma_ultra & 0x0008) && (udma_66))	speed = XFER_UDMA_3;
+	else if (id->dma_ultra & 0x0004)		speed = XFER_UDMA_2;
+	else if (id->dma_ultra & 0x0002)		speed = XFER_UDMA_1;
+	else if (id->dma_ultra & 0x0001)		speed = XFER_UDMA_0;
+	else if (id->dma_mword & 0x0004)		speed = XFER_MW_DMA_2;
+	else if (id->dma_mword & 0x0002)		speed = XFER_MW_DMA_1;
+	else if (id->dma_mword & 0x0001)		speed = XFER_MW_DMA_0;
+	else {
+		set_pio = 1;
+	}
+
+	if (!drive->init_speed)
+		drive->init_speed = speed;
+
+	config_chipset_for_pio(drive, set_pio);
+
+	if (set_pio)
+		return ((int) ide_dma_off_quietly);
+
+	if (cmd680_tune_chipset(drive, speed))
+		return ((int) ide_dma_off);
+
+	rval = (int)(	((id->dma_ultra >> 14) & 3) ? ide_dma_on :
+			((id->dma_ultra >> 11) & 7) ? ide_dma_on :
+			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+			((id->dma_mword >> 8) & 7) ? ide_dma_on :
+			((id->dma_1word >> 8) & 7) ? ide_dma_on :
+						     ide_dma_off_quietly);
+	return rval;
+}
+
+static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
+{
+	if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_CMD_680)
+		return (config_cmd680_chipset_for_dma(drive));
+	return (config_cmd64x_chipset_for_dma(drive, rev, ultra_66));
+}
+
 static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
 {
 	struct hd_driveid *id	= drive->id;
@@ -519,12 +764,15 @@
 	byte can_ultra_33	= 0;
 	byte can_ultra_66	= 0;
 	byte can_ultra_100	= 0;
+	byte can_ultra_133	= 0;
 	ide_dma_action_t dma_func = ide_dma_on;
 
 	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
 	class_rev &= 0xff;	
 
 	switch(dev->device) {
+		case PCI_DEVICE_ID_CMD_680:
+			can_ultra_133 = 1;
 		case PCI_DEVICE_ID_CMD_649:
 			can_ultra_100 = 1;
 		case PCI_DEVICE_ID_CMD_648:
@@ -550,7 +798,7 @@
 		}
 		dma_func = ide_dma_off_quietly;
 		if ((id->field_valid & 4) && (can_ultra_33)) {
-			if (id->dma_ultra & 0x002F) {
+			if (id->dma_ultra & 0x007F) {
 				/* Force if Capable UltraDMA */
 				dma_func = config_chipset_for_dma(drive, class_rev, can_ultra_66);
 				if ((id->field_valid & 2) &&
@@ -586,6 +834,18 @@
 	return HWIF(drive)->dmaproc(dma_func, drive);
 }
 
+static int cmd680_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+	switch (func) {
+		case ide_dma_check:
+			return cmd64x_config_drive_for_dma(drive);
+		default:
+			break;
+	}
+	/* Other cases are done by generic IDE-DMA code. */
+        return ide_dmaproc(func, drive);
+}
+
 static int cmd64x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
 	byte dma_stat		= 0;
@@ -663,7 +923,78 @@
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
-unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name)
+static int cmd680_busproc (ide_drive_t * drive, int state)
+{
+#if 0
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 addr_mask		= (hwif->channel) ? 0xB0 : 0xA0;
+	u32 stat_config		= 0;
+
+        pci_read_config_dword(hwif->pci_dev, addr_mask, &stat_config);
+
+	if (!hwif)
+		return -EINVAL;
+
+	switch (state) {
+		case BUSSTATE_ON:
+			hwif->drives[0].failures = 0;
+			hwif->drives[1].failures = 0;
+			break;
+		case BUSSTATE_OFF:
+			hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+			hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+			break;
+		case BUSSTATE_TRISTATE:
+			hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+			hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+			break;
+		default:
+			return 0;
+	}
+	hwif->bus_state = state;
+#endif
+	return 0;
+}
+
+void cmd680_reset (ide_drive_t *drive)
+{
+#if 0
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 addr_mask		= (hwif->channel) ? 0xB0 : 0xA0;
+	byte reset		= 0;
+
+	pci_read_config_byte(hwif->pci_dev, addr_mask, &reset);
+	pci_write_config_byte(hwif->pci_dev, addr_mask, reset|0x03);
+#endif
+}
+
+unsigned int cmd680_pci_init (struct pci_dev *dev, const char *name)
+{
+	u8 tmpbyte	= 0;	
+	pci_write_config_byte(dev, 0x80, 0x00);
+	pci_write_config_byte(dev, 0x84, 0x00);
+	pci_read_config_byte(dev, 0x8A, &tmpbyte);
+	pci_write_config_byte(dev, 0x8A, tmpbyte|0x01);
+	pci_write_config_word(dev, 0xA2, 0x328A);
+	pci_write_config_dword(dev, 0xA4, 0x328A);
+	pci_write_config_dword(dev, 0xA8, 0x4392);
+	pci_write_config_dword(dev, 0xAC, 0x4009);
+	pci_write_config_word(dev, 0xB2, 0x328A);
+	pci_write_config_dword(dev, 0xB4, 0x328A);
+	pci_write_config_dword(dev, 0xB8, 0x4392);
+	pci_write_config_dword(dev, 0xBC, 0x4009);
+
+#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!cmd64x_proc) {
+		cmd64x_proc = 1;
+		bmide_dev = dev;
+		cmd64x_display_info = &cmd680_get_info;
+	}
+#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_PROC_FS */
+	return 0;
+}
+
+unsigned int cmd64x_pci_init (struct pci_dev *dev, const char *name)
 {
 	unsigned char mrdmode;
 	unsigned int class_rev;
@@ -752,7 +1083,23 @@
 	return 0;
 }
 
-unsigned int __init ata66_cmd64x (ide_hwif_t *hwif)
+unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name)
+{
+	if (dev->device == PCI_DEVICE_ID_CMD_680)
+		return cmd680_pci_init (dev, name);
+	return cmd64x_pci_init (dev, name);
+}
+
+unsigned int cmd680_ata66 (ide_hwif_t *hwif)
+{
+	byte ata66	= 0;
+	byte addr_mask	= (hwif->channel) ? 0xB0 : 0xA0;
+
+	pci_read_config_byte(hwif->pci_dev, addr_mask, &ata66);
+	return (ata66 & 0x01) ? 1 : 0;
+}
+
+unsigned int cmd64x_ata66 (ide_hwif_t *hwif)
 {
 	byte ata66 = 0;
 	byte mask = (hwif->channel) ? 0x02 : 0x01;
@@ -761,6 +1108,14 @@
 	return (ata66 & mask) ? 1 : 0;
 }
 
+unsigned int __init ata66_cmd64x (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev	= hwif->pci_dev;
+	if (dev->device == PCI_DEVICE_ID_CMD_680)
+		return cmd680_ata66(hwif);
+	return cmd64x_ata66(hwif);
+}
+
 void __init ide_init_cmd64x (ide_hwif_t *hwif)
 {
 	struct pci_dev *dev	= hwif->pci_dev;
@@ -769,8 +1124,6 @@
 	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
 	class_rev &= 0xff;
 
-	hwif->tuneproc	= &cmd64x_tuneproc;
-	hwif->speedproc	= &cmd64x_tune_chipset;
 	hwif->drives[0].autotune = 1;
 	hwif->drives[1].autotune = 1;
 
@@ -779,10 +1132,19 @@
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	switch(dev->device) {
+		case PCI_DEVICE_ID_CMD_680:
+			hwif->busproc	= &cmd680_busproc;
+			hwif->dmaproc	= &cmd680_dmaproc;
+			hwif->resetproc = &cmd680_reset;
+			hwif->speedproc	= &cmd680_tune_chipset;
+			hwif->tuneproc	= &cmd680_tuneproc;
+			break;
 		case PCI_DEVICE_ID_CMD_649:
 		case PCI_DEVICE_ID_CMD_648:
 		case PCI_DEVICE_ID_CMD_643:
-			hwif->dmaproc = &cmd64x_dmaproc;
+			hwif->dmaproc	= &cmd64x_dmaproc;
+			hwif->tuneproc	= &cmd64x_tuneproc;
+			hwif->speedproc = &cmd64x_tune_chipset;
 			break;
 		case PCI_DEVICE_ID_CMD_646:
 			hwif->chipset = ide_cmd646;
@@ -791,6 +1153,8 @@
 			} else {
 				hwif->dmaproc = &cmd64x_dmaproc;
 			}
+			hwif->tuneproc	= &cmd64x_tuneproc;
+			hwif->speedproc	= &cmd64x_tune_chipset;
 			break;
 		default:
 			break;
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/hpt366.c linux/drivers/ide/hpt366.c
--- v2.5.2/linux/drivers/ide/hpt366.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/hpt366.c	Tue Jan 15 11:27:30 2002
@@ -1,7 +1,8 @@
 /*
- * linux/drivers/ide/hpt366.c		Version 0.18	June. 9, 2000
+ * linux/drivers/ide/hpt366.c		Version 0.22	20 Sep 2001
  *
  * Copyright (C) 1999-2000		Andre Hedrick <andre@linux-ide.org>
+ * Portions Copyright (C) 2001	        Sun Microsystems, Inc.
  * May be copied or modified under the terms of the GNU General Public License
  *
  * Thanks to HighPoint Technologies for their assistance, and hardware.
@@ -11,6 +12,34 @@
  *
  * Note that final HPT370 support was done by force extraction of GPL.
  *
+ * - add function for getting/setting power status of drive
+ * - the HPT370's state machine can get confused. reset it before each dma 
+ *   xfer to prevent that from happening.
+ * - reset state engine whenever we get an error.
+ * - check for busmaster state at end of dma. 
+ * - use new highpoint timings.
+ * - detect bus speed using highpoint register.
+ * - use pll if we don't have a clock table. added a 66MHz table that's
+ *   just 2x the 33MHz table.
+ * - removed turnaround. NOTE: we never want to switch between pll and
+ *   pci clocks as the chip can glitch in those cases. the highpoint
+ *   approved workaround slows everything down too much to be useful. in
+ *   addition, we would have to serialize access to each chip.
+ * 	Adrian Sun <a.sun@sun.com>
+ *
+ * add drive timings for 66MHz PCI bus,
+ * fix ATA Cable signal detection, fix incorrect /proc info
+ * add /proc display for per-drive PIO/DMA/UDMA mode and
+ * per-channel ATA-33/66 Cable detect.
+ * 	Duncan Laurie <void@sun.com>
+ *
+ * fixup /proc output for multiple controllers
+ *	Tim Hockin <thockin@sun.com>
+ *
+ * On hpt366: 
+ * Reset the hpt366 on error, reset on dma
+ * Fix disabling Fast Interrupt hpt366.
+ * 	Mike Waychison <crlf@sun.com>
  */
 
 #include <linux/config.h>
@@ -28,6 +57,7 @@
 #include <linux/init.h>
 #include <linux/ide.h>
 
+#include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 
@@ -35,6 +65,11 @@
 
 #define DISPLAY_HPT366_TIMINGS
 
+/* various tuning parameters */
+#define HPT_RESET_STATE_ENGINE
+/*#define HPT_DELAY_INTERRUPT*/
+/*#define HPT_SERIALIZE_IO*/
+
 #if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
@@ -106,146 +141,302 @@
 
 struct chipset_bus_clock_list_entry {
 	byte		xfer_speed;
-	unsigned int	chipset_settings_write;
-	unsigned int	chipset_settings_read;
+	unsigned int	chipset_settings;
 };
 
+/* key for bus clock timings
+ * bit
+ * 0:3    data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
+ *        DMA. cycles = value + 1
+ * 4:8    data_low_time. active time of DIOW_/DIOR_ for PIO and MW
+ *        DMA. cycles = value + 1
+ * 9:12   cmd_high_time. inactive time of DIOW_/DIOR_ during task file
+ *        register access.
+ * 13:17  cmd_low_time. active time of DIOW_/DIOR_ during task file
+ *        register access.
+ * 18:21  udma_cycle_time. clock freq and clock cycles for UDMA xfer.
+ *        during task file register access.
+ * 22:24  pre_high_time. time to initialize 1st cycle for PIO and MW DMA
+ *        xfer.
+ * 25:27  cmd_pre_high_time. time to initialize 1st PIO cycle for task
+ *        register access.
+ * 28     UDMA enable
+ * 29     DMA enable
+ * 30     PIO_MST enable. if set, the chip is in bus master mode during
+ *        PIO.
+ * 31     FIFO enable.
+ */
 struct chipset_bus_clock_list_entry forty_base [] = {
 
-	{	XFER_UDMA_4,	0x900fd943,	0x900fd943	},
-	{	XFER_UDMA_3,	0x900ad943,	0x900ad943	},
-	{	XFER_UDMA_2,	0x900bd943,	0x900bd943	},
-	{	XFER_UDMA_1,	0x9008d943,	0x9008d943	},
-	{	XFER_UDMA_0,	0x9008d943,	0x9008d943	},
-
-	{	XFER_MW_DMA_2,	0xa008d943,	0xa008d943	},
-	{	XFER_MW_DMA_1,	0xa010d955,	0xa010d955	},
-	{	XFER_MW_DMA_0,	0xa010d9fc,	0xa010d9fc	},
-
-	{	XFER_PIO_4,	0xc008d963,	0xc008d963	},
-	{	XFER_PIO_3,	0xc010d974,	0xc010d974	},
-	{	XFER_PIO_2,	0xc010d997,	0xc010d997	},
-	{	XFER_PIO_1,	0xc010d9c7,	0xc010d9c7	},
-	{	XFER_PIO_0,	0xc018d9d9,	0xc018d9d9	},
-	{	0,		0x0120d9d9,	0x0120d9d9	}
+	{	XFER_UDMA_4,    0x900fd943	},
+	{	XFER_UDMA_3,	0x900ad943	},
+	{	XFER_UDMA_2,	0x900bd943	},
+	{	XFER_UDMA_1,	0x9008d943	},
+	{	XFER_UDMA_0,	0x9008d943	},
+
+	{	XFER_MW_DMA_2,	0xa008d943	},
+	{	XFER_MW_DMA_1,	0xa010d955	},
+	{	XFER_MW_DMA_0,	0xa010d9fc	},
+
+	{	XFER_PIO_4,	0xc008d963	},
+	{	XFER_PIO_3,	0xc010d974	},
+	{	XFER_PIO_2,	0xc010d997	},
+	{	XFER_PIO_1,	0xc010d9c7	},
+	{	XFER_PIO_0,	0xc018d9d9	},
+	{	0,		0x0120d9d9	}
 };
 
 struct chipset_bus_clock_list_entry thirty_three_base [] = {
 
-	{	XFER_UDMA_4,	0x90c9a731,	0x90c9a731	},
-	{	XFER_UDMA_3,	0x90cfa731,	0x90cfa731	},
-	{	XFER_UDMA_2,	0x90caa731,	0x90caa731	},
-	{	XFER_UDMA_1,	0x90cba731,	0x90cba731	},
-	{	XFER_UDMA_0,	0x90c8a731,	0x90c8a731	},
-
-	{	XFER_MW_DMA_2,	0xa0c8a731,	0xa0c8a731	},
-	{	XFER_MW_DMA_1,	0xa0c8a732,	0xa0c8a732	},	/* 0xa0c8a733 */
-	{	XFER_MW_DMA_0,	0xa0c8a797,	0xa0c8a797	},
-
-	{	XFER_PIO_4,	0xc0c8a731,	0xc0c8a731	},
-	{	XFER_PIO_3,	0xc0c8a742,	0xc0c8a742	},
-	{	XFER_PIO_2,	0xc0d0a753,	0xc0d0a753	},
-	{	XFER_PIO_1,	0xc0d0a7a3,	0xc0d0a7a3	},	/* 0xc0d0a793 */
-	{	XFER_PIO_0,	0xc0d0a7aa,	0xc0d0a7aa	},	/* 0xc0d0a7a7 */
-	{	0,		0x0120a7a7,	0x0120a7a7	}
+	{	XFER_UDMA_4,	0x90c9a731	},
+	{	XFER_UDMA_3,	0x90cfa731	},
+	{	XFER_UDMA_2,	0x90caa731	},
+	{	XFER_UDMA_1,	0x90cba731	},
+	{	XFER_UDMA_0,	0x90c8a731	},
+
+	{	XFER_MW_DMA_2,	0xa0c8a731	},
+	{	XFER_MW_DMA_1,	0xa0c8a732	},	/* 0xa0c8a733 */
+	{	XFER_MW_DMA_0,	0xa0c8a797	},
+
+	{	XFER_PIO_4,	0xc0c8a731	},
+	{	XFER_PIO_3,	0xc0c8a742	},
+	{	XFER_PIO_2,	0xc0d0a753	},
+	{	XFER_PIO_1,	0xc0d0a7a3	},	/* 0xc0d0a793 */
+	{	XFER_PIO_0,	0xc0d0a7aa	},	/* 0xc0d0a7a7 */
+	{	0,		0x0120a7a7	}
 };
 
 struct chipset_bus_clock_list_entry twenty_five_base [] = {
 
-	{	XFER_UDMA_4,	0x90c98521,	0x90c98521	},
-	{	XFER_UDMA_3,	0x90cf8521,	0x90cf8521	},
-	{	XFER_UDMA_2,	0x90cf8521,	0x90cf8521	},
-	{	XFER_UDMA_1,	0x90cb8521,	0x90cb8521	},
-	{	XFER_UDMA_0,	0x90cb8521,	0x90cb8521	},
-
-	{	XFER_MW_DMA_2,	0xa0ca8521,	0xa0ca8521	},
-	{	XFER_MW_DMA_1,	0xa0ca8532,	0xa0ca8532	},
-	{	XFER_MW_DMA_0,	0xa0ca8575,	0xa0ca8575	},
-
-	{	XFER_PIO_4,	0xc0ca8521,	0xc0ca8521	},
-	{	XFER_PIO_3,	0xc0ca8532,	0xc0ca8532	},
-	{	XFER_PIO_2,	0xc0ca8542,	0xc0ca8542	},
-	{	XFER_PIO_1,	0xc0d08572,	0xc0d08572	},
-	{	XFER_PIO_0,	0xc0d08585,	0xc0d08585	},
-	{	0,		0x01208585,	0x01208585	}
+	{	XFER_UDMA_4,	0x90c98521	},
+	{	XFER_UDMA_3,	0x90cf8521	},
+	{	XFER_UDMA_2,	0x90cf8521	},
+	{	XFER_UDMA_1,	0x90cb8521	},
+	{	XFER_UDMA_0,	0x90cb8521	},
+
+	{	XFER_MW_DMA_2,	0xa0ca8521	},
+	{	XFER_MW_DMA_1,	0xa0ca8532	},
+	{	XFER_MW_DMA_0,	0xa0ca8575	},
+
+	{	XFER_PIO_4,	0xc0ca8521	},
+	{	XFER_PIO_3,	0xc0ca8532	},
+	{	XFER_PIO_2,	0xc0ca8542	},
+	{	XFER_PIO_1,	0xc0d08572	},
+	{	XFER_PIO_0,	0xc0d08585	},
+	{	0,		0x01208585	}
+};
+
+#if 1
+/* these are the current (4 sep 2001) timings from highpoint */
+struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
+        {       XFER_UDMA_5,    0x12446231      },
+        {       XFER_UDMA_4,    0x12446231      },
+        {       XFER_UDMA_3,    0x126c6231      },
+        {       XFER_UDMA_2,    0x12486231      },
+        {       XFER_UDMA_1,    0x124c6233      },
+        {       XFER_UDMA_0,    0x12506297      },
+
+        {       XFER_MW_DMA_2,  0x22406c31      },
+        {       XFER_MW_DMA_1,  0x22406c33      },
+        {       XFER_MW_DMA_0,  0x22406c97      },
+
+        {       XFER_PIO_4,     0x06414e31      },
+        {       XFER_PIO_3,     0x06414e42      },
+        {       XFER_PIO_2,     0x06414e53      },
+        {       XFER_PIO_1,     0x06814e93      },
+        {       XFER_PIO_0,     0x06814ea7      },
+        {       0,              0x06814ea7      }
 };
 
+/* 2x 33MHz timings */
+struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
+	{       XFER_UDMA_5,    0x1488e673       },
+	{       XFER_UDMA_4,    0x1488e673       },
+	{       XFER_UDMA_3,    0x1498e673       },
+	{       XFER_UDMA_2,    0x1490e673       },
+	{       XFER_UDMA_1,    0x1498e677       },
+	{       XFER_UDMA_0,    0x14a0e73f       },
+
+	{       XFER_MW_DMA_2,  0x2480fa73       },
+	{       XFER_MW_DMA_1,  0x2480fa77       }, 
+	{       XFER_MW_DMA_0,  0x2480fb3f       },
+
+	{       XFER_PIO_4,     0x0c82be73       },
+	{       XFER_PIO_3,     0x0c82be95       },
+	{       XFER_PIO_2,     0x0c82beb7       },
+	{       XFER_PIO_1,     0x0d02bf37       },
+	{       XFER_PIO_0,     0x0d02bf5f       },
+	{       0,              0x0d02bf5f       }
+};
+#else
+/* from highpoint documentation. these are old values */
 struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
-	{	XFER_UDMA_5,	0x1A85F442,	0x16454e31	},
-	{	XFER_UDMA_4,	0x16454e31,	0x16454e31	},
-	{	XFER_UDMA_3,	0x166d4e31,	0x166d4e31	},
-	{	XFER_UDMA_2,	0x16494e31,	0x16494e31	},
-	{	XFER_UDMA_1,	0x164d4e31,	0x164d4e31	},
-	{	XFER_UDMA_0,	0x16514e31,	0x16514e31	},
-
-	{	XFER_MW_DMA_2,	0x26514e21,	0x26514e21	},
-	{	XFER_MW_DMA_1,	0x26514e33,	0x26514e33	},
-	{	XFER_MW_DMA_0,	0x26514e97,	0x26514e97	},
-
-	{	XFER_PIO_4,	0x06514e21,	0x06514e21	},
-	{	XFER_PIO_3,	0x06514e22,	0x06514e22	},
-	{	XFER_PIO_2,	0x06514e33,	0x06514e33	},
-	{	XFER_PIO_1,	0x06914e43,	0x06914e43	},
-	{	XFER_PIO_0,	0x06914e57,	0x06914e57	},
-	{	0,		0x06514e57,	0x06514e57	}
+	{	XFER_UDMA_5,	0x16454e31	},
+	{	XFER_UDMA_4,	0x16454e31	},
+	{	XFER_UDMA_3,	0x166d4e31	},
+	{	XFER_UDMA_2,	0x16494e31	},
+	{	XFER_UDMA_1,	0x164d4e31	},
+	{	XFER_UDMA_0,	0x16514e31	},
+
+	{	XFER_MW_DMA_2,	0x26514e21	},
+	{	XFER_MW_DMA_1,	0x26514e33	},
+	{	XFER_MW_DMA_0,	0x26514e97	},
+
+	{	XFER_PIO_4,	0x06514e21	},
+	{	XFER_PIO_3,	0x06514e22	},
+	{	XFER_PIO_2,	0x06514e33	},
+	{	XFER_PIO_1,	0x06914e43	},
+	{	XFER_PIO_0,	0x06914e57	},
+	{	0,		0x06514e57	}
+};
+
+struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
+	{       XFER_UDMA_5,    0x14846231      },
+	{       XFER_UDMA_4,    0x14886231      },
+	{       XFER_UDMA_3,    0x148c6231      },
+	{       XFER_UDMA_2,    0x148c6231      },
+	{       XFER_UDMA_1,    0x14906231      },
+	{       XFER_UDMA_0,    0x14986231      },
+	
+	{       XFER_MW_DMA_2,  0x26514e21      },
+	{       XFER_MW_DMA_1,  0x26514e33      },
+	{       XFER_MW_DMA_0,  0x26514e97      },
+	
+	{       XFER_PIO_4,     0x06514e21      },
+	{       XFER_PIO_3,     0x06514e22      },
+	{       XFER_PIO_2,     0x06514e33      },
+	{       XFER_PIO_1,     0x06914e43      },
+	{       XFER_PIO_0,     0x06914e57      },
+	{       0,              0x06514e57      }
+};
+#endif
+
+struct chipset_bus_clock_list_entry fifty_base_hpt370[] = {
+	{       XFER_UDMA_5,    0x12848242      },
+	{       XFER_UDMA_4,    0x12ac8242      },
+	{       XFER_UDMA_3,    0x128c8242      },
+	{       XFER_UDMA_2,    0x120c8242      },
+	{       XFER_UDMA_1,    0x12148254      },
+	{       XFER_UDMA_0,    0x121882ea      },
+
+	{       XFER_MW_DMA_2,  0x22808242      },
+	{       XFER_MW_DMA_1,  0x22808254      },
+	{       XFER_MW_DMA_0,  0x228082ea      },
+
+	{       XFER_PIO_4,     0x0a81f442      },
+	{       XFER_PIO_3,     0x0a81f443      },
+	{       XFER_PIO_2,     0x0a81f454      },
+	{       XFER_PIO_1,     0x0ac1f465      },
+	{       XFER_PIO_0,     0x0ac1f48a      },
+	{       0,              0x0ac1f48a      }
 };
 
 #define HPT366_DEBUG_DRIVE_INFO		0
 #define HPT370_ALLOW_ATA100_5		1
 #define HPT366_ALLOW_ATA66_4		1
 #define HPT366_ALLOW_ATA66_3		1
+#define HPT366_MAX_DEVS			8
+
+#define F_LOW_PCI_33      0x23
+#define F_LOW_PCI_40      0x29
+#define F_LOW_PCI_50      0x2d
+#define F_LOW_PCI_66      0x42
+
+static struct pci_dev *hpt_devs[HPT366_MAX_DEVS];
+static int n_hpt_devs;
+
+static unsigned int pci_rev_check_hpt3xx(struct pci_dev *dev);
+static unsigned int pci_rev2_check_hpt3xx(struct pci_dev *dev);
+byte hpt366_proc = 0;
+byte hpt363_shared_irq;
+byte hpt363_shared_pin;
+extern char *ide_xfer_verbose (byte xfer_rate);
 
 #if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
 static int hpt366_get_info(char *, char **, off_t, int);
 extern int (*hpt366_display_info)(char *, char **, off_t, int); /* ide-proc.c */
 extern char *ide_media_verbose(ide_drive_t *);
-static struct pci_dev *bmide_dev;
-static struct pci_dev *bmide2_dev;
 
 static int hpt366_get_info (char *buffer, char **addr, off_t offset, int count)
 {
-	char *p		= buffer;
-	u32 bibma	= bmide_dev->resource[4].start;
-	u32 bibma2 	= bmide2_dev->resource[4].start;
-	char *chipset_names[] = {"HPT366", "HPT366", "HPT368", "HPT370", "HPT370A"};
-	u8  c0 = 0, c1 = 0;
-	u32 class_rev;
-
-	pci_read_config_dword(bmide_dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-
-        /*
-         * at that point bibma+0x2 et bibma+0xa are byte registers
-         * to investigate:
-         */
-	c0 = inb_p((unsigned short)bibma + 0x02);
-	if (bmide2_dev)
-		c1 = inb_p((unsigned short)bibma2 + 0x02);
-
-	p += sprintf(p, "\n                                %s Chipset.\n", chipset_names[class_rev]);
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-	p += sprintf(p, "                %sabled                         %sabled\n",
-			(c0&0x80) ? "dis" : " en",
-			(c1&0x80) ? "dis" : " en");
-	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
-	p += sprintf(p, "DMA enabled:    %s              %s             %s               %s\n",
-			(c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ",
-			(c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " );
-
-	p += sprintf(p, "UDMA\n");
-	p += sprintf(p, "DMA\n");
-	p += sprintf(p, "PIO\n");
+	char *p	= buffer;
+	char *chipset_nums[] = {"366", "366", "368", "370", "370A"};
+	int i;
+
+	p += sprintf(p, "\n                             "
+		"HighPoint HPT366/368/370\n");
+	for (i = 0; i < n_hpt_devs; i++) {
+		struct pci_dev *dev = hpt_devs[i];
+		unsigned short iobase = dev->resource[4].start;
+		u32 class_rev;
+		u8 c0, c1;
+
+		pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+		class_rev &= 0xff;
+
+		p += sprintf(p, "\nController: %d\n", i);
+		p += sprintf(p, "Chipset: HPT%s\n", chipset_nums[class_rev]);
+		p += sprintf(p, "--------------- Primary Channel "
+				"--------------- Secondary Channel "
+				"--------------\n");
+
+		/* get the bus master status registers */
+		c0 = inb_p(iobase + 0x2);
+		c1 = inb_p(iobase + 0xa);
+		p += sprintf(p, "Enabled:        %s"
+				"                             %s\n",
+			(c0 & 0x80) ? "no" : "yes",
+			(c1 & 0x80) ? "no" : "yes");
+
+		if (pci_rev_check_hpt3xx(dev)) {
+			u8 cbl;
+			cbl = inb_p(iobase + 0x7b);
+			outb_p(cbl | 1, iobase + 0x7b);
+			outb_p(cbl & ~1, iobase + 0x7b);
+			cbl = inb_p(iobase + 0x7a);
+			p += sprintf(p, "Cable:          ATA-%d"
+					"                          ATA-%d\n",
+				(cbl & 0x02) ? 33 : 66,
+				(cbl & 0x01) ? 33 : 66);
+			p += sprintf(p, "\n");
+		}
 
+		p += sprintf(p, "--------------- drive0 --------- drive1 "
+				"------- drive0 ---------- drive1 -------\n");
+		p += sprintf(p, "DMA capable:    %s              %s" 
+				"            %s               %s\n",
+			(c0 & 0x20) ? "yes" : "no ", 
+			(c0 & 0x40) ? "yes" : "no ",
+			(c1 & 0x20) ? "yes" : "no ", 
+			(c1 & 0x40) ? "yes" : "no ");
+
+		{
+			u8 c2, c3;
+			/* older revs don't have these registers mapped 
+			 * into io space */
+			pci_read_config_byte(dev, 0x43, &c0);
+			pci_read_config_byte(dev, 0x47, &c1);
+			pci_read_config_byte(dev, 0x4b, &c2);
+			pci_read_config_byte(dev, 0x4f, &c3);
+
+			p += sprintf(p, "Mode:           %s             %s"
+					"           %s              %s\n",
+				(c0 & 0x10) ? "UDMA" : (c0 & 0x20) ? "DMA " : 
+					(c0 & 0x80) ? "PIO " : "off ",
+				(c1 & 0x10) ? "UDMA" : (c1 & 0x20) ? "DMA " :
+					(c1 & 0x80) ? "PIO " : "off ",
+				(c2 & 0x10) ? "UDMA" : (c2 & 0x20) ? "DMA " :
+					(c2 & 0x80) ? "PIO " : "off ",
+				(c3 & 0x10) ? "UDMA" : (c3 & 0x20) ? "DMA " :
+					(c3 & 0x80) ? "PIO " : "off ");
+		}
+	}
+	p += sprintf(p, "\n");
+	
 	return p-buffer;/* => must be less than 4k! */
 }
 #endif  /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
 
-byte hpt366_proc = 0;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-byte hpt363_shared_irq;
-byte hpt363_shared_pin;
-
 static unsigned int pci_rev_check_hpt3xx (struct pci_dev *dev)
 {
 	unsigned int class_rev;
@@ -282,16 +473,16 @@
 	return 0;
 }
 
-static unsigned int pci_bus_clock_list (byte speed, int direction, struct chipset_bus_clock_list_entry * chipset_table)
+static unsigned int pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
 {
 	for ( ; chipset_table->xfer_speed ; chipset_table++)
 		if (chipset_table->xfer_speed == speed) {
-			return (direction) ? chipset_table->chipset_settings_write : chipset_table->chipset_settings_read;
+			return chipset_table->chipset_settings;
 		}
-	return (direction) ? chipset_table->chipset_settings_write : chipset_table->chipset_settings_read;
+	return chipset_table->chipset_settings;
 }
 
-static void hpt366_tune_chipset (ide_drive_t *drive, byte speed, int direction)
+static void hpt366_tune_chipset (ide_drive_t *drive, byte speed)
 {
 	byte regtime		= (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
 	byte regfast		= (HWIF(drive)->channel) ? 0x55 : 0x51;
@@ -304,7 +495,7 @@
 	byte drive_fast		= 0;
 
 	/*
-	 * Disable the "fast interrupt" prediction.
+	 * Disable the "fast interrupt" prediction. 
 	 */
 	pci_read_config_byte(HWIF(drive)->pci_dev, regfast, &drive_fast);
 	if (drive_fast & 0x02)
@@ -314,16 +505,22 @@
 	/* detect bus speed by looking at control reg timing: */
 	switch((reg1 >> 8) & 7) {
 		case 5:
-			reg2 = pci_bus_clock_list(speed, direction, forty_base);
+			reg2 = pci_bus_clock_list(speed, forty_base);
 			break;
 		case 9:
-			reg2 = pci_bus_clock_list(speed, direction, twenty_five_base);
+			reg2 = pci_bus_clock_list(speed, twenty_five_base);
 			break;
 		default:
 		case 7:
-			reg2 = pci_bus_clock_list(speed, direction, thirty_three_base);
+			reg2 = pci_bus_clock_list(speed, thirty_three_base);
 			break;
 	}
+#if 0
+	/* this is a nice idea ... */
+	list_conf = pci_bus_clock_list(speed,
+				       (struct chipset_bus_clock_list_entry *)
+				       dev->sysdata);
+#endif
 	/*
 	 * Disable on-chip PIO FIFO/buffer (to avoid problems handling I/O errors later)
 	 */
@@ -337,40 +534,47 @@
 	pci_write_config_dword(HWIF(drive)->pci_dev, regtime, reg2);
 }
 
-static void hpt370_tune_chipset (ide_drive_t *drive, byte speed, int direction)
+static void hpt370_tune_chipset (ide_drive_t *drive, byte speed)
 {
 	byte regfast		= (HWIF(drive)->channel) ? 0x55 : 0x51;
-	byte reg5bh		= (speed != XFER_UDMA_5) ? 0x22 : (direction) ? 0x20 : 0x22;
-	unsigned int list_conf	= pci_bus_clock_list(speed, direction, thirty_three_base_hpt370);
+	unsigned int list_conf	= 0;
 	unsigned int drive_conf = 0;
 	unsigned int conf_mask	= (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
-	byte drive_pci		= 0;
-	byte drive_fast		= 0;
+	byte drive_pci		= 0x40 + (drive->dn * 4);
+	byte new_fast, drive_fast		= 0;
+	struct pci_dev *dev 	= HWIF(drive)->pci_dev;
 
-	switch (drive->dn) {
-		case 0: drive_pci = 0x40; break;
-		case 1: drive_pci = 0x44; break;
-		case 2: drive_pci = 0x48; break;
-		case 3: drive_pci = 0x4c; break;
-		default: return;
-	}
 	/*
 	 * Disable the "fast interrupt" prediction.
+	 * don't holdoff on interrupts. (== 0x01 despite what the docs say) 
 	 */
-	pci_read_config_byte(HWIF(drive)->pci_dev, regfast, &drive_fast);
-	if (drive_fast & 0x80)
-		pci_write_config_byte(HWIF(drive)->pci_dev, regfast, drive_fast & ~0x80);
+	pci_read_config_byte(dev, regfast, &drive_fast);
+	new_fast = drive_fast;
+	if (new_fast & 0x02)
+		new_fast &= ~0x02;
+
+#ifdef HPT_DELAY_INTERRUPT
+	if (new_fast & 0x01)
+		new_fast &= ~0x01;
+#else
+	if ((new_fast & 0x01) == 0)
+		new_fast |= 0x01;
+#endif
+	if (new_fast != drive_fast)
+		pci_write_config_byte(HWIF(drive)->pci_dev, regfast, new_fast);
 
-	pci_read_config_dword(HWIF(drive)->pci_dev, drive_pci, &drive_conf);
-	pci_write_config_byte(HWIF(drive)->pci_dev, 0x5b, reg5bh);
+	list_conf = pci_bus_clock_list(speed, 
+				       (struct chipset_bus_clock_list_entry *)
+				       dev->sysdata);
 
+	pci_read_config_dword(dev, drive_pci, &drive_conf);
 	list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
-	/*
-	 * Disable on-chip PIO FIFO/buffer (to avoid problems handling I/O errors later)
-	 */
-	list_conf &= ~0x80000000;
+	
+	if (speed < XFER_MW_DMA_0) {
+		list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
+	}
 
-	pci_write_config_dword(HWIF(drive)->pci_dev, drive_pci, list_conf);
+	pci_write_config_dword(dev, drive_pci, list_conf);
 }
 
 static int hpt3xx_tune_chipset (ide_drive_t *drive, byte speed)
@@ -382,9 +586,9 @@
 		drive->init_speed = speed;
 
 	if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) {
-		hpt370_tune_chipset(drive, speed, 0);
+		hpt370_tune_chipset(drive, speed);
         } else {
-                hpt366_tune_chipset(drive, speed, 0);
+                hpt366_tune_chipset(drive, speed);
         }
 	drive->current_speed = speed;
 	return ((int) ide_config_drive_speed(drive, speed));
@@ -541,13 +745,6 @@
 	}
 }
 
-void hpt370_rw_proc (ide_drive_t *drive, ide_dma_action_t func)
-{
-	if ((func != ide_dma_write) || (func != ide_dma_read))
-		return;
-	hpt370_tune_chipset(drive, drive->current_speed, (func == ide_dma_write));
-}
-
 static int config_drive_xfer_rate (ide_drive_t *drive)
 {
 	struct hd_driveid *id = drive->id;
@@ -624,6 +821,13 @@
 				reg50h, reg52h, reg5ah);
 			if (reg5ah & 0x10)
 				pci_write_config_byte(HWIF(drive)->pci_dev, 0x5a, reg5ah & ~0x10);
+			/* fall through to a reset */
+#if 0
+		case ide_dma_begin:
+		case ide_dma_end:
+			/* reset the chips state over and over.. */
+			pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, 0x13);
+#endif
 			break;
 		case ide_dma_timeout:
 		default:
@@ -634,9 +838,52 @@
 
 int hpt370_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned long dma_base = hwif->dma_base;
+	byte regstate = hwif->channel ? 0x54 : 0x50;
+	byte reginfo = hwif->channel ? 0x56 : 0x52;
+	byte dma_stat;
+
 	switch (func) {
 		case ide_dma_check:
 			return config_drive_xfer_rate(drive);
+		case ide_dma_test_irq:	/* returns 1 if dma irq issued, 0 otherwise */
+			dma_stat = inb(dma_base+2);
+			return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
+
+		case ide_dma_end:
+			dma_stat = inb(dma_base + 2);
+			if (dma_stat & 0x01) {
+				udelay(20); /* wait a little */
+				dma_stat = inb(dma_base + 2);
+			}
+			if ((dma_stat & 0x01) == 0) 
+				break;
+
+			func = ide_dma_timeout;
+			/* fallthrough */
+
+		case ide_dma_timeout:
+		case ide_dma_lostirq:
+			pci_read_config_byte(hwif->pci_dev, reginfo, 
+					     &dma_stat); 
+			printk("%s: %d bytes in FIFO\n", drive->name, 
+			       dma_stat);
+			pci_write_config_byte(hwif->pci_dev, regstate, 0x37);
+			udelay(10);
+			dma_stat = inb(dma_base);
+			outb(dma_stat & ~0x1, dma_base); /* stop dma */
+			dma_stat = inb(dma_base + 2); 
+			outb(dma_stat | 0x6, dma_base+2); /* clear errors */
+			/* fallthrough */
+
+#ifdef HPT_RESET_STATE_ENGINE
+	        case ide_dma_begin:
+#endif
+			pci_write_config_byte(hwif->pci_dev, regstate, 0x37);
+			udelay(10);
+			break;
+
 		default:
 			break;
 	}
@@ -644,6 +891,212 @@
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
+/*
+ * Since SUN Cobalt is attempting to do this operation, I should disclose
+ * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
+ * HOTSWAP ATA Infrastructure.
+ */
+void hpt3xx_reset (ide_drive_t *drive)
+{
+#if 0
+	unsigned long high_16	= pci_resource_start(HWIF(drive)->pci_dev, 4);
+	byte reset		= (HWIF(drive)->channel) ? 0x80 : 0x40;
+	byte reg59h		= 0;
+
+	pci_read_config_byte(HWIF(drive)->pci_dev, 0x59, &reg59h);
+	pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h|reset);
+	pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h);
+#endif
+}
+
+#if 0
+static int hpt3xx_tristate (ide_drive_t * drive, int state)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	byte reset		= (hwif->channel) ? 0x80 : 0x40;
+	byte state_reg		= (hwif->channel) ? 0x57 : 0x53;
+	byte reg59h		= 0;
+	byte regXXh		= 0;
+
+	if (!hwif)
+		return -EINVAL;
+
+//	hwif->bus_state = state;
+
+	pci_read_config_byte(dev, 0x59, &reg59h);
+	pci_read_config_byte(dev, state_reg, &regXXh);
+
+	if (state) {
+		(void) ide_do_reset(drive);
+		pci_write_config_byte(dev, state_reg, regXXh|0x80);
+		pci_write_config_byte(dev, 0x59, reg59h|reset);
+	} else {
+		pci_write_config_byte(dev, 0x59, reg59h & ~(reset));
+		pci_write_config_byte(dev, state_reg, regXXh & ~(0x80));
+		(void) ide_do_reset(drive);
+	}
+	return 0;
+}
+#endif
+
+/* 
+ * set/get power state for a drive.
+ * turning the power off does the following things:
+ *   1) soft-reset the drive
+ *   2) tri-states the ide bus
+ *
+ * when we turn things back on, we need to re-initialize things.
+ */
+#define TRISTATE_BIT  0x8000
+static int hpt370_busproc(ide_drive_t * drive, int state)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	byte tristate, resetmask, bus_reg;
+	u16 tri_reg;
+
+	if (!hwif)
+		return -EINVAL;
+
+	hwif->bus_state = state;
+
+	if (hwif->channel) { 
+		/* secondary channel */
+		tristate = 0x56;
+		resetmask = 0x80; 
+	} else { 
+		/* primary channel */
+		tristate = 0x52;
+		resetmask = 0x40;
+	}
+
+	/* grab status */
+	pci_read_config_word(hwif->pci_dev, tristate, &tri_reg);
+	pci_read_config_byte(hwif->pci_dev, 0x59, &bus_reg);
+
+	/* set the state. we don't set it if we don't need to do so.
+	 * make sure that the drive knows that it has failed if it's off */
+	switch (state) {
+	case BUSSTATE_ON:
+		hwif->drives[0].failures = 0;
+		hwif->drives[1].failures = 0;
+		if ((bus_reg & resetmask) == 0)
+			return 0;
+		tri_reg &= ~TRISTATE_BIT;
+		bus_reg &= ~resetmask;
+		break;
+	case BUSSTATE_OFF:
+		hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+		hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+		if ((tri_reg & TRISTATE_BIT) == 0 && (bus_reg & resetmask))
+			return 0;
+		tri_reg &= ~TRISTATE_BIT;
+		bus_reg |= resetmask;
+		break;
+	case BUSSTATE_TRISTATE:
+		hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+		hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+		if ((tri_reg & TRISTATE_BIT) && (bus_reg & resetmask))
+			return 0;
+		tri_reg |= TRISTATE_BIT;
+		bus_reg |= resetmask;
+		break;
+	}
+	pci_write_config_byte(hwif->pci_dev, 0x59, bus_reg);
+	pci_write_config_word(hwif->pci_dev, tristate, tri_reg);
+
+	return 0;
+}
+
+static void __init init_hpt370(struct pci_dev *dev)
+{
+	int adjust, i;
+	u16 freq;
+	u32 pll;
+	byte reg5bh;
+
+	/*
+	 * default to pci clock. make sure MA15/16 are set to output
+	 * to prevent drives having problems with 40-pin cables.
+	 */
+	pci_write_config_byte(dev, 0x5b, 0x23);
+
+	/*
+	 * set up the PLL. we need to adjust it so that it's stable. 
+	 * freq = Tpll * 192 / Tpci
+	 */
+	pci_read_config_word(dev, 0x78, &freq);
+	freq &= 0x1FF;
+	if (freq < 0x9c) {
+		pll = F_LOW_PCI_33;
+		dev->sysdata = (void *) thirty_three_base_hpt370;
+		printk("HPT370: using 33MHz PCI clock\n");
+	} else if (freq < 0xb0) {
+		pll = F_LOW_PCI_40;
+	} else if (freq < 0xc8) {
+		pll = F_LOW_PCI_50;
+		dev->sysdata = (void *) fifty_base_hpt370;
+		printk("HPT370: using 50MHz PCI clock\n");
+	} else {
+		pll = F_LOW_PCI_66;
+		dev->sysdata = (void *) sixty_six_base_hpt370;
+		printk("HPT370: using 66MHz PCI clock\n");
+	}
+	
+	/*
+	 * only try the pll if we don't have a table for the clock
+	 * speed that we're running at. NOTE: the internal PLL will
+	 * result in slow reads when using a 33MHz PCI clock. we also
+	 * don't like to use the PLL because it will cause glitches
+	 * on PRST/SRST when the HPT state engine gets reset.
+	 */
+	if (dev->sysdata) 
+		goto init_hpt370_done;
+	
+	/*
+	 * adjust PLL based upon PCI clock, enable it, and wait for
+	 * stabilization.
+	 */
+	adjust = 0;
+	freq = (pll < F_LOW_PCI_50) ? 2 : 4;
+	while (adjust++ < 6) {
+		pci_write_config_dword(dev, 0x5c, (freq + pll) << 16 |
+				       pll | 0x100);
+
+		/* wait for clock stabilization */
+		for (i = 0; i < 0x50000; i++) {
+			pci_read_config_byte(dev, 0x5b, &reg5bh);
+			if (reg5bh & 0x80) {
+				/* spin looking for the clock to destabilize */
+				for (i = 0; i < 0x1000; ++i) {
+					pci_read_config_byte(dev, 0x5b, 
+							     &reg5bh);
+					if ((reg5bh & 0x80) == 0)
+						goto pll_recal;
+				}
+				pci_read_config_dword(dev, 0x5c, &pll);
+				pci_write_config_dword(dev, 0x5c, 
+						       pll & ~0x100);
+				pci_write_config_byte(dev, 0x5b, 0x21);
+				dev->sysdata = (void *) fifty_base_hpt370;
+				printk("HPT370: using 50MHz internal PLL\n");
+				goto init_hpt370_done;
+			}
+		}
+pll_recal:
+		if (adjust & 1)
+			pll -= (adjust >> 1);
+		else
+			pll += (adjust >> 1);
+	} 
+
+init_hpt370_done:
+	/* reset state engine */
+	pci_write_config_byte(dev, 0x50, 0x37); 
+	pci_write_config_byte(dev, 0x54, 0x37); 
+	udelay(100);
+}
+
 unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name)
 {
 	byte test = 0;
@@ -652,14 +1105,8 @@
 		pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
 
 	pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &test);
-
-#if 0
-	if (test != 0x08)
-		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x08);
-#else
 	if (test != (L1_CACHE_BYTES / 4))
 		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
-#endif
 
 	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &test);
 	if (test != 0x78)
@@ -673,17 +1120,18 @@
 	if (test != 0x08)
 		pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
 
+	if (pci_rev_check_hpt3xx(dev)) {
+		init_hpt370(dev);
+		hpt_devs[n_hpt_devs++] = dev;
+	} else {
+		hpt_devs[n_hpt_devs++] = dev;
+	}
+	
 #if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
 	if (!hpt366_proc) {
 		hpt366_proc = 1;
-		bmide_dev = dev;
-		if (pci_rev_check_hpt3xx(dev))
-			bmide2_dev = dev;
 		hpt366_display_info = &hpt366_get_info;
 	}
-	if ((hpt366_proc) && ((dev->devfn - bmide_dev->devfn) == 1)) {
-		bmide2_dev = dev;
-	}
 #endif /* DISPLAY_HPT366_TIMINGS && CONFIG_PROC_FS */
 
 	return dev->irq;
@@ -691,38 +1139,58 @@
 
 unsigned int __init ata66_hpt366 (ide_hwif_t *hwif)
 {
-	byte ata66 = 0;
+	byte ata66	= 0;
+	byte regmask	= (hwif->channel) ? 0x01 : 0x02;
 
 	pci_read_config_byte(hwif->pci_dev, 0x5a, &ata66);
 #ifdef DEBUG
 	printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n",
-		ata66, (ata66 & 0x02) ? "33" : "66",
+		ata66, (ata66 & regmask) ? "33" : "66",
 		PCI_FUNC(hwif->pci_dev->devfn));
 #endif /* DEBUG */
-	return ((ata66 & 0x02) ? 0 : 1);
+	return ((ata66 & regmask) ? 0 : 1);
 }
 
 void __init ide_init_hpt366 (ide_hwif_t *hwif)
 {
+	int hpt_rev;
+
 	hwif->tuneproc	= &hpt3xx_tune_drive;
 	hwif->speedproc	= &hpt3xx_tune_chipset;
 	hwif->quirkproc	= &hpt3xx_quirkproc;
 	hwif->intrproc	= &hpt3xx_intrproc;
 	hwif->maskproc	= &hpt3xx_maskproc;
 
+#ifdef HPT_SERIALIZE_IO
+	/* serialize access to this device */
+	if (hwif->mate)
+		hwif->serialized = hwif->mate->serialized = 1;
+#endif
+
+	hpt_rev = pci_rev_check_hpt3xx(hwif->pci_dev);
+	if (hpt_rev) {
+		/* set up ioctl for power status. note: power affects both
+		 * drives on each channel */
+		hwif->busproc   = &hpt370_busproc;
+	}
+
 	if (pci_rev2_check_hpt3xx(hwif->pci_dev)) {
 		/* do nothing now but will split device types */
+		hwif->resetproc = &hpt3xx_reset;
+/*
+ * don't do until we can parse out the cobalt box argh ...
+ *		hwif->busproc   = &hpt3xx_tristate;
+ */
 	}
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (hwif->dma_base) {
-		if (pci_rev_check_hpt3xx(hwif->pci_dev)) {
+		if (hpt_rev) {
 			byte reg5ah = 0;
 			pci_read_config_byte(hwif->pci_dev, 0x5a, &reg5ah);
 			if (reg5ah & 0x10)	/* interrupt force enable */
 				pci_write_config_byte(hwif->pci_dev, 0x5a, reg5ah & ~0x10);
 			hwif->dmaproc = &hpt370_dmaproc;
-			hwif->rwproc = &hpt370_rw_proc;
 		} else {
 			hwif->dmaproc = &hpt366_dmaproc;
 		}
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/ide-cd.c linux/drivers/ide/ide-cd.c
--- v2.5.2/linux/drivers/ide/ide-cd.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/ide/ide-cd.c	Tue Jan 15 11:27:30 2002
@@ -2911,11 +2911,7 @@
 	return 0;
 }
 
-static
-int ide_cdrom_reinit (ide_drive_t *drive)
-{
-	return 0;
-}
+int ide_cdrom_reinit (ide_drive_t *drive);
 
 static ide_driver_t ide_cdrom_driver = {
 	name:			"ide-cdrom",
@@ -2925,6 +2921,8 @@
 	supports_dma:		1,
 	supports_dsc_overlap:	1,
 	cleanup:		ide_cdrom_cleanup,
+	standby:		NULL,
+	flushcache:		NULL,
 	do_request:		ide_do_rw_cdrom,
 	end_request:		NULL,
 	ioctl:			ide_cdrom_ioctl,
@@ -2952,6 +2950,39 @@
 
 MODULE_PARM(ignore, "s");
 MODULE_DESCRIPTION("ATAPI CD-ROM Driver");
+
+int ide_cdrom_reinit (ide_drive_t *drive)
+{
+	struct cdrom_info *info;
+	int failed = 0;
+
+	MOD_INC_USE_COUNT;
+	info = (struct cdrom_info *) kmalloc (sizeof (struct cdrom_info), GFP_KERNEL);
+	if (info == NULL) {
+		printk ("%s: Can't allocate a cdrom structure\n", drive->name);
+		return 1;
+	}
+	if (ide_register_subdriver (drive, &ide_cdrom_driver, IDE_SUBDRIVER_VERSION)) {
+		printk ("%s: Failed to register the driver with ide.c\n", drive->name);
+		kfree (info);
+		return 1;
+	}
+	memset (info, 0, sizeof (struct cdrom_info));
+	drive->driver_data = info;
+	DRIVER(drive)->busy++;
+	if (ide_cdrom_setup (drive)) {
+		DRIVER(drive)->busy--;
+		if (ide_cdrom_cleanup (drive))
+			printk ("%s: ide_cdrom_cleanup failed in ide_cdrom_init\n", drive->name);
+		return 1;
+	}
+	DRIVER(drive)->busy--;
+	failed--;
+
+	ide_register_module(&ide_cdrom_module);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
 
 static void __exit ide_cdrom_exit(void)
 {
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/ide-cd.h linux/drivers/ide/ide-cd.h
--- v2.5.2/linux/drivers/ide/ide-cd.h	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/ide-cd.h	Sat Jan 19 14:30:41 2002
@@ -38,7 +38,9 @@
 /************************************************************************/
 
 #define SECTOR_BITS 		9
+#ifndef SECTOR_SIZE
 #define SECTOR_SIZE		(1 << SECTOR_BITS)
+#endif
 #define SECTORS_PER_FRAME	(CD_FRAMESIZE >> SECTOR_BITS)
 #define SECTOR_BUFFER_SIZE	(CD_FRAMESIZE * 32)
 #define SECTORS_BUFFER		(SECTOR_BUFFER_SIZE >> SECTOR_BITS)
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/ide-cs.c linux/drivers/ide/ide-cs.c
--- v2.5.2/linux/drivers/ide/ide-cs.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/ide-cs.c	Tue Jan 15 11:27:30 2002
@@ -227,16 +227,15 @@
 #define CFG_CHECK(fn, args...) \
 if (CardServices(fn, args) != 0) goto next_entry
 
-int idecs_register (int io_base, int ctl_base, int irq)
+int idecs_register (int arg1, int arg2, int irq)
 {
         hw_regs_t hw;
-        ide_init_hwif_ports(&hw, (ide_ioreg_t) io_base, (ide_ioreg_t) ctl_base, NULL);
+        ide_init_hwif_ports(&hw, (ide_ioreg_t) arg1, (ide_ioreg_t) arg2, NULL);
         hw.irq = irq;
-        hw.chipset = ide_pci; // this enables IRQ sharing w/ PCI irqs
+        hw.chipset = ide_pci; /* this enables IRQ sharing w/ PCI irqs */
         return ide_register_hw(&hw, NULL);
 }
 
-
 void ide_config(dev_link_t *link)
 {
     client_handle_t handle = link->handle;
@@ -338,15 +337,15 @@
     if (link->io.NumPorts2)
 	release_region(link->io.BasePort2, link->io.NumPorts2);
 
-    /* disable drive interrupts during IDE probe */
-    if(ctl_base)
-    	outb(0x02, ctl_base);
-
     /* retry registration in case device is still spinning up */
     for (i = 0; i < 10; i++) {
+	if (ctl_base)
+	    outb(0x02, ctl_base); /* Set nIEN = disable device interrupts */
 	hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ);
 	if (hd >= 0) break;
 	if (link->io.NumPorts1 == 0x20) {
+	    if (ctl_base)
+		outb(0x02, ctl_base+0x10);
 	    hd = idecs_register(io_base+0x10, ctl_base+0x10,
 			      link->irq.AssignedIRQ);
 	    if (hd >= 0) {
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/ide-disk.c linux/drivers/ide/ide-disk.c
--- v2.5.2/linux/drivers/ide/ide-disk.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/ide/ide-disk.c	Thu Jan 17 13:58:35 2002
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/ide/ide-disk.c	Version 1.10	June 9, 2000
+ *  linux/drivers/ide/ide-disk.c	Version 1.13	Nov 28, 2001
  *
  *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
  */
@@ -28,9 +28,11 @@
  *			added UDMA 3/4 reporting
  * Version 1.10		request queue changes, Ultra DMA 100
  * Version 1.11		Highmem I/O support, Jens Axboe <axboe@suse.de>
+ * Version 1.12		added 48-bit lba
+ * Version 1.13		adding taskfile io access method
  */
 
-#define IDEDISK_VERSION	"1.11"
+#define IDEDISK_VERSION	"1.13"
 
 #undef REALLY_SLOW_IO		/* most systems can safely undef this */
 
@@ -60,33 +62,6 @@
 #define IS_PDC4030_DRIVE (0)	/* auto-NULLs out pdc4030 code */
 #endif
 
-static void idedisk_bswap_data (void *buffer, int wcount)
-{
-	u16 *p = buffer;
-
-	while (wcount--) {
-		*p = *p << 8 | *p >> 8; p++;
-		*p = *p << 8 | *p >> 8; p++;
-	}
-}
-
-inline void idedisk_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
-{
-	ide_input_data(drive, buffer, wcount);
-	if (drive->bswap)
-		idedisk_bswap_data(buffer, wcount);
-}
-
-static inline void idedisk_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
-{
-	if (drive->bswap) {
-		idedisk_bswap_data(buffer, wcount);
-		ide_output_data(drive, buffer, wcount);
-		idedisk_bswap_data(buffer, wcount);
-	} else
-		ide_output_data(drive, buffer, wcount);
-}
-
 /*
  * lba_capacity_is_ok() performs a sanity check on the claimed "lba_capacity"
  * value for this drive (from its reported identification information).
@@ -100,6 +75,11 @@
 {
 	unsigned long lba_sects, chs_sects, head, tail;
 
+	if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)) {
+		printk("48-bit Drive: %llu \n", id->lba_capacity_2);
+		return 1;
+	}
+
 	/*
 	 * The ATA spec tells large drives to return
 	 * C/H/S = 16383/16/63 independent of their size.
@@ -132,367 +112,285 @@
 	return 0;	/* lba_capacity value may be bad */
 }
 
-/*
- * read_intr() is the handler for disk read/multread interrupts
- */
-static ide_startstop_t read_intr (ide_drive_t *drive)
-{
-	byte stat;
-	int i;
-	unsigned int msect, nsect;
-	unsigned long flags;
-	struct request *rq;
-	char *to;
-
-	/* new way for dealing with premature shared PCI interrupts */
-	if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
-		if (stat & (ERR_STAT|DRQ_STAT)) {
-			return ide_error(drive, "read_intr", stat);
-		}
-		/* no data yet, so wait for another interrupt */
-		ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
-		return ide_started;
-	}
-
-	msect = drive->mult_count;
-read_next:
-	rq = HWGROUP(drive)->rq;
-	if (msect) {
-		if ((nsect = rq->current_nr_sectors) > msect)
-			nsect = msect;
-		msect -= nsect;
-	} else
-		nsect = 1;
-	to = ide_map_buffer(rq, &flags);
-	idedisk_input_data(drive, to, nsect * SECTOR_WORDS);
-#ifdef DEBUG
-	printk("%s:  read: sectors(%ld-%ld), buffer=0x%08lx, remaining=%ld\n",
-		drive->name, rq->sector, rq->sector+nsect-1,
-		(unsigned long) rq->buffer+(nsect<<9), rq->nr_sectors-nsect);
-#endif
-	ide_unmap_buffer(to, &flags);
-	rq->sector += nsect;
-	rq->errors = 0;
-	i = (rq->nr_sectors -= nsect);
-	if (((long)(rq->current_nr_sectors -= nsect)) <= 0)
-		ide_end_request(1, HWGROUP(drive));
-	if (i > 0) {
-		if (msect)
-			goto read_next;
-		ide_set_handler (drive, &read_intr, WAIT_CMD, NULL);
-                return ide_started;
-	}
-        return ide_stopped;
-}
+static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block);
+static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block);
+static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block);
 
 /*
- * write_intr() is the handler for disk write interrupts
+ * do_rw_disk() issues READ and WRITE commands to a disk,
+ * using LBA if supported, or CHS otherwise, to address sectors.
+ * It also takes care of issuing special DRIVE_CMDs.
  */
-static ide_startstop_t write_intr (ide_drive_t *drive)
+static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
-	byte stat;
-	int i;
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	struct request *rq = hwgroup->rq;
+	if (rq->flags & REQ_CMD)
+		goto good_command;
 
-	if (!OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
-		printk("%s: write_intr error1: nr_sectors=%ld, stat=0x%02x\n", drive->name, rq->nr_sectors, stat);
-        } else {
-#ifdef DEBUG
-		printk("%s: write: sector %ld, buffer=0x%08lx, remaining=%ld\n",
-			drive->name, rq->sector, (unsigned long) rq->buffer,
-			rq->nr_sectors-1);
-#endif
-		if ((rq->nr_sectors == 1) ^ ((stat & DRQ_STAT) != 0)) {
-			rq->sector++;
-			rq->errors = 0;
-			i = --rq->nr_sectors;
-			--rq->current_nr_sectors;
-			if (((long)rq->current_nr_sectors) <= 0)
-				ide_end_request(1, hwgroup);
-			if (i > 0) {
-				unsigned long flags;
-				char *to = ide_map_buffer(rq, &flags);
-				idedisk_output_data (drive, to, SECTOR_WORDS);
-				ide_unmap_buffer(to, &flags);
-				ide_set_handler (drive, &write_intr, WAIT_CMD, NULL);
-                                return ide_started;
-			}
-                        return ide_stopped;
-		}
-		return ide_stopped;	/* the original code did this here (?) */
-	}
-	return ide_error(drive, "write_intr", stat);
-}
+	blk_dump_rq_flags(rq, "do_rw_disk, bad command");
+	ide_end_request(0, HWGROUP(drive));
+	return ide_stopped;
 
-/*
- * ide_multwrite() transfers a block of up to mcount sectors of data
- * to a drive as part of a disk multiple-sector write operation.
- *
- * Returns 0 on success.
- *
- * Note that we may be called from two contexts - the do_rw_disk context
- * and IRQ context. The IRQ can happen any time after we've output the
- * full "mcount" number of sectors, so we must make sure we update the
- * state _before_ we output the final part of the data!
- */
-int ide_multwrite (ide_drive_t *drive, unsigned int mcount)
-{
- 	ide_hwgroup_t	*hwgroup= HWGROUP(drive);
- 	struct request	*rq = &hwgroup->wrq;
- 
-  	do {
-  		char *buffer;
-  		int nsect = rq->current_nr_sectors;
-		unsigned long flags;
-
-		if (nsect > mcount)
-			nsect = mcount;
-		mcount -= nsect;
-
-		buffer = ide_map_buffer(rq, &flags);
-		rq->sector += nsect;
-		rq->nr_sectors -= nsect;
-		rq->current_nr_sectors -= nsect;
-
-		/* Do we move to the next bh after this? */
-		if (!rq->current_nr_sectors) {
-			struct bio *bio = rq->bio->bi_next;
-
-			/* end early early we ran out of requests */
-			if (!bio) {
-				mcount = 0;
-			} else {
-				rq->bio = bio;
-				rq->current_nr_sectors = bio_sectors(bio);
-				rq->hard_cur_sectors = rq->current_nr_sectors;
-			}
-		}
+good_command:
 
-		/*
-		 * Ok, we're all setup for the interrupt
-		 * re-entering us on the last transfer.
-		 */
-		idedisk_output_data(drive, buffer, nsect<<7);
-		ide_unmap_buffer(buffer, &flags);
-	} while (mcount);
+#ifdef CONFIG_BLK_DEV_PDC4030
+	if (IS_PDC4030_DRIVE) {
+		extern ide_startstop_t promise_rw_disk(ide_drive_t *, struct request *, unsigned long);
+		return promise_rw_disk(drive, rq, block);
+	}
+#endif /* CONFIG_BLK_DEV_PDC4030 */
 
-        return 0;
-}
+	if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing))	/* 48-bit LBA */
+		return lba_48_rw_disk(drive, rq, (unsigned long long) block);
+	if (drive->select.b.lba)		/* 28-bit LBA */
+		return lba_28_rw_disk(drive, rq, (unsigned long) block);
 
-/*
- * multwrite_intr() is the handler for disk multwrite interrupts
- */
-static ide_startstop_t multwrite_intr (ide_drive_t *drive)
-{
-	byte stat;
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	struct request *rq = &hwgroup->wrq;
-
-	if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
-		if (stat & DRQ_STAT) {
-			/*
-			 *	The drive wants data. Remember rq is the copy
-			 *	of the request
-			 */
-			if (rq->nr_sectors) {
-				if (ide_multwrite(drive, drive->mult_count))
-					return ide_stopped;
-				ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL);
-				return ide_started;
-			}
-		} else {
-			/*
-			 *	If the copy has all the blocks completed then
-			 *	we can end the original request.
-			 */
-			if (!rq->nr_sectors) {	/* all done? */
-				rq = hwgroup->rq;
-
-				__ide_end_request(hwgroup, 1, rq->nr_sectors);
-				return ide_stopped;
-			}
-		}
-		return ide_stopped;	/* the original code did this here (?) */
-	}
-	return ide_error(drive, "multwrite_intr", stat);
+	/* 28-bit CHS : DIE DIE DIE piece of legacy crap!!! */
+	return chs_rw_disk(drive, rq, (unsigned long) block);
 }
 
-/*
- * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
- */
-static ide_startstop_t set_multmode_intr (ide_drive_t *drive)
+static task_ioreg_t get_command (ide_drive_t *drive, int cmd)
 {
-	byte stat;
+	int lba48bit = (drive->id->cfs_enable_2 & 0x0400) ? 1 : 0;
 
-	if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT)) {
-		drive->mult_count = drive->mult_req;
-	} else {
-		drive->mult_req = drive->mult_count = 0;
-		drive->special.b.recalibrate = 1;
-		(void) ide_dump_status(drive, "set_multmode", stat);
-	}
-	return ide_stopped;
+#if 1
+	lba48bit = drive->addressing;
+#endif
+
+	if ((cmd == READ) && (drive->using_dma))
+		return (lba48bit) ? WIN_READDMA_EXT : WIN_READDMA;
+	else if ((cmd == READ) && (drive->mult_count))
+		return (lba48bit) ? WIN_MULTREAD_EXT : WIN_MULTREAD;
+	else if (cmd == READ)
+		return (lba48bit) ? WIN_READ_EXT : WIN_READ;
+	else if ((cmd == WRITE) && (drive->using_dma))
+		return (lba48bit) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
+	else if ((cmd == WRITE) && (drive->mult_count))
+		return (lba48bit) ? WIN_MULTWRITE_EXT : WIN_MULTWRITE;
+	else if (cmd == WRITE)
+		return (lba48bit) ? WIN_WRITE_EXT : WIN_WRITE;
+	else
+		return WIN_NOP;
 }
 
-/*
- * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
- */
-static ide_startstop_t set_geometry_intr (ide_drive_t *drive)
+static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
-	byte stat;
+	struct hd_drive_task_hdr	taskfile;
+	struct hd_drive_hob_hdr		hobfile;
+	ide_task_t			args;
+	int				sectors;
+
+	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));
+
+	unsigned int track	= (block / drive->sect);
+	unsigned int sect	= (block % drive->sect) + 1;
+	unsigned int head	= (track % drive->head);
+	unsigned int cyl	= (track / drive->head);
+
+	memset(&taskfile, 0, sizeof(task_struct_t));
+	memset(&hobfile, 0, sizeof(hob_struct_t));
+
+	sectors = rq->nr_sectors;
+	if (sectors == 256)
+		sectors = 0;
+	if (command == WIN_MULTWRITE_EXT || command == WIN_MULTWRITE) {
+		sectors = drive->mult_count;
+		if (sectors > rq->current_nr_sectors)
+			sectors = rq->current_nr_sectors;
+	}
+
+	taskfile.sector_count	= sectors;
+	taskfile.sector_number	= sect;
+	taskfile.low_cylinder	= cyl;
+	taskfile.high_cylinder	= (cyl>>8);
+	taskfile.device_head	= head;
+	taskfile.device_head	|= drive->select.all;
+	taskfile.command	= command;
 
-	if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT))
-		return ide_stopped;
+#ifdef DEBUG
+	printk("%s: %sing: ", drive->name,
+		(rq_data_dir(rq)==READ) ? "read" : "writ");
+	if (lba)	printk("LBAsect=%lld, ", block);
+	else		printk("CHS=%d/%d/%d, ", cyl, head, sect);
+	printk("sectors=%ld, ", rq->nr_sectors);
+	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
+#endif
 
-	if (stat & (ERR_STAT|DRQ_STAT))
-		return ide_error(drive, "set_geometry_intr", stat);
+	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
+	memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
+	args.command_type	= ide_cmd_type_parser(&args);
+	args.prehandler		= ide_pre_handler_parser(&taskfile, &hobfile);
+	args.handler		= ide_handler_parser(&taskfile, &hobfile);
+	args.posthandler	= NULL;
+	args.rq			= (struct request *) rq;
+	args.block		= block;
+	rq->special		= NULL;
+	rq->special		= (ide_task_t *)&args;
+
+	return do_rw_taskfile(drive, &args);
+}
+
+static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+	struct hd_drive_task_hdr	taskfile;
+	struct hd_drive_hob_hdr		hobfile;
+	ide_task_t			args;
+	int				sectors;
+
+	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));
+
+	sectors = rq->nr_sectors;
+	if (sectors == 256)
+		sectors = 0;
+	if (command == WIN_MULTWRITE_EXT || command == WIN_MULTWRITE) {
+		sectors = drive->mult_count;
+		if (sectors > rq->current_nr_sectors)
+			sectors = rq->current_nr_sectors;
+	}
+
+	memset(&taskfile, 0, sizeof(task_struct_t));
+	memset(&hobfile, 0, sizeof(hob_struct_t));
+
+	taskfile.sector_count	= sectors;
+	taskfile.sector_number	= block;
+	taskfile.low_cylinder	= (block>>=8);
+	taskfile.high_cylinder	= (block>>=8);
+	taskfile.device_head	= ((block>>8)&0x0f);
+	taskfile.device_head	|= drive->select.all;
+	taskfile.command	= command;
 
-	ide_set_handler(drive, &set_geometry_intr, WAIT_CMD, NULL);
-	return ide_started;	
-}
+#ifdef DEBUG
+	printk("%s: %sing: ", drive->name,
+		(rq_data_dir(rq)==READ) ? "read" : "writ");
+	if (lba)	printk("LBAsect=%lld, ", block);
+	else		printk("CHS=%d/%d/%d, ", cyl, head, sect);
+	printk("sectors=%ld, ", rq->nr_sectors);
+	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
+#endif
 
-/*
- * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
- */
-static ide_startstop_t recal_intr (ide_drive_t *drive)
-{
-	byte stat = GET_STAT();
+	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
+	memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
+	args.command_type	= ide_cmd_type_parser(&args);
+	args.prehandler		= ide_pre_handler_parser(&taskfile, &hobfile);
+	args.handler		= ide_handler_parser(&taskfile, &hobfile);
+	args.posthandler	= NULL;
+	args.rq			= (struct request *) rq;
+	args.block		= block;
+	rq->special		= NULL;
+	rq->special		= (ide_task_t *)&args;
 
-	if (!OK_STAT(stat,READY_STAT,BAD_STAT))
-		return ide_error(drive, "recal_intr", stat);
-	return ide_stopped;
+	return do_rw_taskfile(drive, &args);
 }
 
 /*
- * do_rw_disk() issues READ and WRITE commands to a disk,
- * using LBA if supported, or CHS otherwise, to address sectors.
- * It also takes care of issuing special DRIVE_CMDs.
+ * 268435455  == 137439 MB or 28bit limit
+ * 320173056  == 163929 MB or 48bit addressing
+ * 1073741822 == 549756 MB or 48bit addressing fake drive
  */
-static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+
+static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block)
 {
-	unsigned long flags;
+	struct hd_drive_task_hdr	taskfile;
+	struct hd_drive_hob_hdr		hobfile;
+	ide_task_t			args;
+	int				sectors;
+
+	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));
+
+	memset(&taskfile, 0, sizeof(task_struct_t));
+	memset(&hobfile, 0, sizeof(hob_struct_t));
+
+	sectors = rq->nr_sectors;
+	if (sectors == 256)
+		sectors = 0;
+	if (command == WIN_MULTWRITE_EXT || command == WIN_MULTWRITE) {
+		sectors = drive->mult_count;
+		if (sectors > rq->current_nr_sectors)
+			sectors = rq->current_nr_sectors;
+	}
+
+	taskfile.sector_count	= sectors;
+	hobfile.sector_count	= sectors >> 8;
+
+	if (rq->nr_sectors == 65536) {
+		taskfile.sector_count	= 0x00;
+		hobfile.sector_count	= 0x00;
+	}
+
+	taskfile.sector_number	= block;	/* low lba */
+	taskfile.low_cylinder	= (block>>=8);	/* mid lba */
+	taskfile.high_cylinder	= (block>>=8);	/* hi  lba */
+	hobfile.sector_number	= (block>>=8);	/* low lba */
+	hobfile.low_cylinder	= (block>>=8);	/* mid lba */
+	hobfile.high_cylinder	= (block>>=8);	/* hi  lba */
+	taskfile.device_head	= drive->select.all;
+	hobfile.device_head	= taskfile.device_head;
+	hobfile.control		= (drive->ctl|0x80);
+	taskfile.command	= command;
 
-	if (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
-	OUT_BYTE(0x00, IDE_FEATURE_REG);
-	OUT_BYTE(rq->nr_sectors,IDE_NSECTOR_REG);
-#ifdef CONFIG_BLK_DEV_PDC4030
-	if (drive->select.b.lba || IS_PDC4030_DRIVE) {
-#else /* !CONFIG_BLK_DEV_PDC4030 */
-	if (drive->select.b.lba) {
-#endif /* CONFIG_BLK_DEV_PDC4030 */
-#ifdef DEBUG
-		printk("%s: %sing: LBAsect=%ld, sectors=%ld, buffer=0x%08lx\n",
-			drive->name, (rq_data_dir(rq)==READ)?"read":"writ",
-			block, rq->nr_sectors, (unsigned long) rq->buffer);
-#endif
-		OUT_BYTE(block,IDE_SECTOR_REG);
-		OUT_BYTE(block>>=8,IDE_LCYL_REG);
-		OUT_BYTE(block>>=8,IDE_HCYL_REG);
-		OUT_BYTE(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG);
-	} else {
-		unsigned int sect,head,cyl,track;
-		track = block / drive->sect;
-		sect  = block % drive->sect + 1;
-		OUT_BYTE(sect,IDE_SECTOR_REG);
-		head  = track % drive->head;
-		cyl   = track / drive->head;
-		OUT_BYTE(cyl,IDE_LCYL_REG);
-		OUT_BYTE(cyl>>8,IDE_HCYL_REG);
-		OUT_BYTE(head|drive->select.all,IDE_SELECT_REG);
 #ifdef DEBUG
-		printk("%s: %sing: CHS=%d/%d/%d, sectors=%ld, buffer=0x%08lx\n",
-			drive->name, (rq_data_dir(rq)==READ)?"read":"writ", cyl,
-			head, sect, rq->nr_sectors, (unsigned long) rq->buffer);
+	printk("%s: %sing: ", drive->name,
+		(rq_data_dir(rq)==READ) ? "read" : "writ");
+	if (lba)	printk("LBAsect=%lld, ", block);
+	else		printk("CHS=%d/%d/%d, ", cyl, head, sect);
+	printk("sectors=%ld, ", rq->nr_sectors);
+	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
 #endif
-	}
-#ifdef CONFIG_BLK_DEV_PDC4030
-	if (IS_PDC4030_DRIVE) {
-		extern ide_startstop_t do_pdc4030_io(ide_drive_t *, struct request *);
-		return do_pdc4030_io (drive, rq);
-	}
-#endif /* CONFIG_BLK_DEV_PDC4030 */
-	if (rq_data_dir(rq) == READ) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive)))
-			return ide_started;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
-		OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG);
-		return ide_started;
-	}
-	if (rq_data_dir(rq) == WRITE) {
-		ide_startstop_t startstop;
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_write, drive)))
-			return ide_started;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, IDE_COMMAND_REG);
-		if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
-			printk(KERN_ERR "%s: no DRQ after issuing %s\n", drive->name,
-				drive->mult_count ? "MULTWRITE" : "WRITE");
-			return startstop;
-		}
-		if (!drive->unmask)
-			__cli();	/* local CPU only */
-		if (drive->mult_count) {
-			ide_hwgroup_t *hwgroup = HWGROUP(drive);
-			/*
-			 * Ugh.. this part looks ugly because we MUST set up
-			 * the interrupt handler before outputting the first block
-			 * of data to be written.  If we hit an error (corrupted buffer list)
-			 * in ide_multwrite(), then we need to remove the handler/timer
-			 * before returning.  Fortunately, this NEVER happens (right?).
-			 *
-			 * Except when you get an error it seems...
-			 */
-			hwgroup->wrq = *rq; /* scratchpad */
-			ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL);
-			if (ide_multwrite(drive, drive->mult_count)) {
-				spin_lock_irqsave(&ide_lock, flags);
-				hwgroup->handler = NULL;
-				del_timer(&hwgroup->timer);
-				spin_unlock_irqrestore(&ide_lock, flags);
-				return ide_stopped;
-			}
-		} else {
-			char *buffer = ide_map_buffer(rq, &flags);
-			ide_set_handler (drive, &write_intr, WAIT_CMD, NULL);
-			idedisk_output_data(drive, buffer, SECTOR_WORDS);
-			ide_unmap_buffer(buffer, &flags);
-		}
-		return ide_started;
-	}
-	printk(KERN_ERR "%s: bad command: %lx\n", drive->name, rq->flags);
-	ide_end_request(0, HWGROUP(drive));
-	return ide_stopped;
+
+	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
+	memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
+	args.command_type	= ide_cmd_type_parser(&args);
+	args.prehandler		= ide_pre_handler_parser(&taskfile, &hobfile);
+	args.handler		= ide_handler_parser(&taskfile, &hobfile);
+	args.posthandler	= NULL;
+	args.rq			= (struct request *) rq;
+	args.block		= block;
+	rq->special		= NULL;
+	rq->special		= (ide_task_t *)&args;
+
+	return do_rw_taskfile(drive, &args);
 }
 
 static int idedisk_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
 {
 	MOD_INC_USE_COUNT;
 	if (drive->removable && drive->usage == 1) {
+		struct hd_drive_task_hdr taskfile;
+		struct hd_drive_hob_hdr hobfile;
+		memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+		memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
 		check_disk_change(inode->i_rdev);
+		taskfile.command = WIN_DOORLOCK;
 		/*
 		 * Ignore the return code from door_lock,
 		 * since the open() has already succeeded,
 		 * and the door_lock is irrelevant at this point.
 		 */
-		if (drive->doorlocking && ide_wait_cmd(drive, WIN_DOORLOCK, 0, 0, 0, NULL))
+		if (drive->doorlocking &&
+		    ide_wait_taskfile(drive, &taskfile, &hobfile, NULL))
 			drive->doorlocking = 0;
 	}
 	return 0;
 }
 
+static int do_idedisk_flushcache(ide_drive_t *drive);
+
 static void idedisk_release (struct inode *inode, struct file *filp, ide_drive_t *drive)
 {
 	if (drive->removable && !drive->usage) {
+		struct hd_drive_task_hdr taskfile;
+		struct hd_drive_hob_hdr hobfile;
+		memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+		memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
 		invalidate_bdev(inode->i_bdev, 0);
+		taskfile.command = WIN_DOORUNLOCK;
 		if (drive->doorlocking &&
-		    ide_wait_cmd(drive, WIN_DOORUNLOCK, 0, 0, 0, NULL))
+		    ide_wait_taskfile(drive, &taskfile, &hobfile, NULL))
 			drive->doorlocking = 0;
 	}
+	if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
+		if (do_idedisk_flushcache(drive))
+			printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n",
+				drive->name);
 	MOD_DEC_USE_COUNT;
 }
 
@@ -507,27 +405,234 @@
 }
 
 /*
+ * Queries for true maximum capacity of the drive.
+ * Returns maximum LBA address (> 0) of the drive, 0 if failed.
+ */
+static unsigned long idedisk_read_native_max_address(ide_drive_t *drive)
+{
+	ide_task_t args;
+	unsigned long addr = 0;
+
+	if (!(drive->id->command_set_1 & 0x0400) &&
+	    !(drive->id->cfs_enable_2 & 0x0100))
+		return addr;
+
+	/* Create IDE/ATA command request structure */
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_SELECT_OFFSET]	= 0x40;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_READ_NATIVE_MAX;
+	args.handler				= task_no_data_intr;
+
+	/* submit command request */
+	ide_raw_taskfile(drive, &args, NULL);
+
+	/* if OK, compute maximum address value */
+	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+		addr = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24)
+		     | ((args.tfRegister[  IDE_HCYL_OFFSET]       ) << 16)
+		     | ((args.tfRegister[  IDE_LCYL_OFFSET]       ) <<  8)
+		     | ((args.tfRegister[IDE_SECTOR_OFFSET]       ));
+	}
+	addr++;	/* since the return value is (maxlba - 1), we add 1 */
+	return addr;
+}
+
+static unsigned long long idedisk_read_native_max_address_ext(ide_drive_t *drive)
+{
+	ide_task_t args;
+	unsigned long long addr = 0;
+
+	/* Create IDE/ATA command request structure */
+	memset(&args, 0, sizeof(ide_task_t));
+
+	args.tfRegister[IDE_SELECT_OFFSET]	= 0x40;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_READ_NATIVE_MAX_EXT;
+	args.handler				= task_no_data_intr;
+
+        /* submit command request */
+        ide_raw_taskfile(drive, &args, NULL);
+
+	/* if OK, compute maximum address value */
+	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+		u32 high = ((args.hobRegister[IDE_HCYL_OFFSET_HOB])<<16) |
+			   ((args.hobRegister[IDE_LCYL_OFFSET_HOB])<<8) |
+  			    (args.hobRegister[IDE_SECTOR_OFFSET_HOB]); 
+		u32 low  = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
+			   ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
+			    (args.tfRegister[IDE_SECTOR_OFFSET]);
+		addr = ((__u64)high << 24) | low;
+	}
+	addr++;	/* since the return value is (maxlba - 1), we add 1 */
+	return addr;
+}
+
+#ifdef CONFIG_IDEDISK_STROKE
+/*
+ * Sets maximum virtual LBA address of the drive.
+ * Returns new maximum virtual LBA address (> 0) or 0 on failure.
+ */
+static unsigned long idedisk_set_max_address(ide_drive_t *drive, unsigned long addr_req)
+{
+	ide_task_t args;
+	unsigned long addr_set = 0;
+	
+	addr_req--;
+	/* Create IDE/ATA command request structure */
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_SECTOR_OFFSET]	= ((addr_req >>  0) & 0xff);
+	args.tfRegister[IDE_LCYL_OFFSET]	= ((addr_req >>  8) & 0xff);
+	args.tfRegister[IDE_HCYL_OFFSET]	= ((addr_req >> 16) & 0xff);
+	args.tfRegister[IDE_SELECT_OFFSET]	= ((addr_req >> 24) & 0x0f) | 0x40;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SET_MAX;
+	args.handler				= task_no_data_intr;
+	/* submit command request */
+	ide_raw_taskfile(drive, &args, NULL);
+	/* if OK, read new maximum address value */
+	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+		addr_set = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24)
+			 | ((args.tfRegister[  IDE_HCYL_OFFSET]       ) << 16)
+			 | ((args.tfRegister[  IDE_LCYL_OFFSET]       ) <<  8)
+			 | ((args.tfRegister[IDE_SECTOR_OFFSET]       ));
+	}
+	addr_set++;
+	return addr_set;
+}
+
+static unsigned long long idedisk_set_max_address_ext(ide_drive_t *drive, unsigned long long addr_req)
+{
+	ide_task_t args;
+	unsigned long long addr_set = 0;
+
+	addr_req--;
+	/* Create IDE/ATA command request structure */
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_SECTOR_OFFSET]	= ((addr_req >>  0) & 0xff);
+	args.tfRegister[IDE_LCYL_OFFSET]	= ((addr_req >>= 8) & 0xff);
+	args.tfRegister[IDE_HCYL_OFFSET]	= ((addr_req >>= 8) & 0xff);
+	args.tfRegister[IDE_SELECT_OFFSET]      = 0x40;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SET_MAX_EXT;
+	args.hobRegister[IDE_SECTOR_OFFSET_HOB]	= ((addr_req >>= 8) & 0xff);
+	args.hobRegister[IDE_LCYL_OFFSET_HOB]	= ((addr_req >>= 8) & 0xff);
+	args.hobRegister[IDE_HCYL_OFFSET_HOB]	= ((addr_req >>= 8) & 0xff);
+	args.hobRegister[IDE_SELECT_OFFSET_HOB]	= 0x40;
+	args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80);
+        args.handler				= task_no_data_intr;
+	/* submit command request */
+	ide_raw_taskfile(drive, &args, NULL);
+	/* if OK, compute maximum address value */
+	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+		u32 high = ((args.hobRegister[IDE_HCYL_OFFSET_HOB])<<16) |
+			   ((args.hobRegister[IDE_LCYL_OFFSET_HOB])<<8) |
+			    (args.hobRegister[IDE_SECTOR_OFFSET_HOB]);
+		u32 low  = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
+			   ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
+			    (args.tfRegister[IDE_SECTOR_OFFSET]);
+		addr_set = ((__u64)high << 24) | low;
+	}
+	return addr_set;
+}
+
+/*
+ * Tests if the drive supports Host Protected Area feature.
+ * Returns true if supported, false otherwise.
+ */
+static inline int idedisk_supports_host_protected_area(ide_drive_t *drive)
+{
+	int flag = (drive->id->cfs_enable_1 & 0x0400) ? 1 : 0;
+	printk("%s: host protected area => %d\n", drive->name, flag);
+	return flag;
+}
+
+#endif /* CONFIG_IDEDISK_STROKE */
+
+/*
  * Compute drive->capacity, the full capacity of the drive
  * Called with drive->id != NULL.
+ *
+ * To compute capacity, this uses either of
+ *
+ *    1. CHS value set by user       (whatever user sets will be trusted)
+ *    2. LBA value from target drive (require new ATA feature)
+ *    3. LBA value from system BIOS  (new one is OK, old one may break)
+ *    4. CHS value from system BIOS  (traditional style)
+ *
+ * in above order (i.e., if value of higher priority is available,
+ * reset will be ignored).
  */
 static void init_idedisk_capacity (ide_drive_t  *drive)
 {
 	struct hd_driveid *id = drive->id;
 	unsigned long capacity = drive->cyl * drive->head * drive->sect;
+	unsigned long set_max = idedisk_read_native_max_address(drive);
+	unsigned long long capacity_2 = capacity;
+	unsigned long long set_max_ext;
 
+	drive->capacity48 = 0;
 	drive->select.b.lba = 0;
 
+	if (id->cfs_enable_2 & 0x0400) {
+		capacity_2 = id->lba_capacity_2;
+		drive->cyl = (unsigned int) capacity_2 / (drive->head * drive->sect);
+		drive->head		= drive->bios_head = 255;
+		drive->sect		= drive->bios_sect = 63;
+		drive->select.b.lba	= 1;
+		set_max_ext = idedisk_read_native_max_address_ext(drive);
+		if (set_max_ext > capacity_2) {
+#ifdef CONFIG_IDEDISK_STROKE
+			set_max_ext = idedisk_read_native_max_address_ext(drive);
+			set_max_ext = idedisk_set_max_address_ext(drive, set_max_ext);
+			if (set_max_ext) {
+				drive->capacity48 = capacity_2 = set_max_ext;
+				drive->cyl = (unsigned int) set_max_ext / (drive->head * drive->sect);
+				drive->select.b.lba = 1;
+				drive->id->lba_capacity_2 = capacity_2;
+                        }
+#else /* !CONFIG_IDEDISK_STROKE */
+			printk("%s: setmax_ext LBA %llu, native  %llu\n",
+				drive->name, set_max_ext, capacity_2);
+#endif /* CONFIG_IDEDISK_STROKE */
+		}
+		drive->bios_cyl		= drive->cyl;
+		drive->capacity48	= capacity_2;
+		drive->capacity		= (unsigned long) capacity_2;
+		return;
 	/* Determine capacity, and use LBA if the drive properly supports it */
-	if ((id->capability & 2) && lba_capacity_is_ok(id)) {
+	} else if ((id->capability & 2) && lba_capacity_is_ok(id)) {
 		capacity = id->lba_capacity;
 		drive->cyl = capacity / (drive->head * drive->sect);
 		drive->select.b.lba = 1;
 	}
+
+	if (set_max > capacity) {
+#ifdef CONFIG_IDEDISK_STROKE
+		set_max = idedisk_read_native_max_address(drive);
+		set_max = idedisk_set_max_address(drive, set_max);
+		if (set_max) {
+			drive->capacity = capacity = set_max;
+			drive->cyl = set_max / (drive->head * drive->sect);
+			drive->select.b.lba = 1;
+			drive->id->lba_capacity = capacity;
+		}
+#else /* !CONFIG_IDEDISK_STROKE */
+		printk("%s: setmax LBA %lu, native  %lu\n",
+			drive->name, set_max, capacity);
+#endif /* CONFIG_IDEDISK_STROKE */
+	}
+
 	drive->capacity = capacity;
+
+	if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)) {
+                drive->capacity48 = id->lba_capacity_2;
+		drive->head = 255;
+		drive->sect = 63;
+		drive->cyl = (unsigned long)(drive->capacity48) / (drive->head * drive->sect);
+	}
 }
 
-static unsigned long idedisk_capacity (ide_drive_t  *drive)
+static unsigned long idedisk_capacity (ide_drive_t *drive)
 {
+	if (drive->id->cfs_enable_2 & 0x0400)
+		return (drive->capacity48 - drive->sect0);
 	return (drive->capacity - drive->sect0);
 }
 
@@ -536,23 +641,48 @@
 	special_t *s = &drive->special;
 
 	if (s->b.set_geometry) {
-		s->b.set_geometry = 0;
-		OUT_BYTE(drive->sect,IDE_SECTOR_REG);
-		OUT_BYTE(drive->cyl,IDE_LCYL_REG);
-		OUT_BYTE(drive->cyl>>8,IDE_HCYL_REG);
-		OUT_BYTE(((drive->head-1)|drive->select.all)&0xBF,IDE_SELECT_REG);
-		if (!IS_PDC4030_DRIVE)
-			ide_cmd(drive, WIN_SPECIFY, drive->sect, &set_geometry_intr);
+		struct hd_drive_task_hdr taskfile;
+		struct hd_drive_hob_hdr hobfile;
+		ide_handler_t *handler = NULL;
+
+		memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+		memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+
+		s->b.set_geometry	= 0;
+		taskfile.sector_number	= drive->sect;
+		taskfile.low_cylinder	= drive->cyl;
+		taskfile.high_cylinder	= drive->cyl>>8;
+		taskfile.device_head	= ((drive->head-1)|drive->select.all)&0xBF;
+		if (!IS_PDC4030_DRIVE) {
+			taskfile.sector_count	= drive->sect;
+			taskfile.command	= WIN_SPECIFY;
+			handler			= ide_handler_parser(&taskfile, &hobfile);
+		}
+		do_taskfile(drive, &taskfile, &hobfile, handler);
 	} else if (s->b.recalibrate) {
 		s->b.recalibrate = 0;
-		if (!IS_PDC4030_DRIVE)
-			ide_cmd(drive, WIN_RESTORE, drive->sect, &recal_intr);
+		if (!IS_PDC4030_DRIVE) {
+			struct hd_drive_task_hdr taskfile;
+			struct hd_drive_hob_hdr hobfile;
+			memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+			memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+			taskfile.sector_count	= drive->sect;
+			taskfile.command	= WIN_RESTORE;
+			do_taskfile(drive, &taskfile, &hobfile, ide_handler_parser(&taskfile, &hobfile));
+		}
 	} else if (s->b.set_multmode) {
 		s->b.set_multmode = 0;
 		if (drive->id && drive->mult_req > drive->id->max_multsect)
 			drive->mult_req = drive->id->max_multsect;
-		if (!IS_PDC4030_DRIVE)
-			ide_cmd(drive, WIN_SETMULT, drive->mult_req, &set_multmode_intr);
+		if (!IS_PDC4030_DRIVE) {
+			struct hd_drive_task_hdr taskfile;
+			struct hd_drive_hob_hdr hobfile;
+			memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+			memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+			taskfile.sector_count	= drive->mult_req;
+			taskfile.command	= WIN_SETMULT;
+			do_taskfile(drive, &taskfile, &hobfile, &set_multmode_intr);
+		}
 	} else if (s->all) {
 		int special = s->all;
 		s->all = 0;
@@ -564,9 +694,11 @@
 
 static void idedisk_pre_reset (ide_drive_t *drive)
 {
+	int legacy = (drive->id->cfs_enable_2 & 0x0400) ? 0 : 1;
+
 	drive->special.all = 0;
-	drive->special.b.set_geometry = 1;
-	drive->special.b.recalibrate  = 1;
+	drive->special.b.set_geometry = legacy;
+	drive->special.b.recalibrate  = legacy;
 	if (OK_TO_RESET_CONTROLLER)
 		drive->mult_count = 0;
 	if (!drive->keep_settings && !drive->using_dma)
@@ -579,19 +711,45 @@
 
 static int smart_enable(ide_drive_t *drive)
 {
-	return ide_wait_cmd(drive, WIN_SMART, 0, SMART_ENABLE, 0, NULL);
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+	taskfile.feature	= SMART_ENABLE;
+	taskfile.low_cylinder	= SMART_LCYL_PASS;
+	taskfile.high_cylinder	= SMART_HCYL_PASS;
+	taskfile.command	= WIN_SMART;
+	return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
 }
 
 static int get_smart_values(ide_drive_t *drive, byte *buf)
 {
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+	taskfile.feature	= SMART_READ_VALUES;
+	taskfile.sector_count	= 0x01;
+	taskfile.low_cylinder	= SMART_LCYL_PASS;
+	taskfile.high_cylinder	= SMART_HCYL_PASS;
+	taskfile.command	= WIN_SMART;
 	(void) smart_enable(drive);
-	return ide_wait_cmd(drive, WIN_SMART, 0, SMART_READ_VALUES, 1, buf);
+	return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
 }
 
 static int get_smart_thresholds(ide_drive_t *drive, byte *buf)
 {
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+	taskfile.feature	= SMART_READ_THRESHOLDS;
+	taskfile.sector_count	= 0x01;
+	taskfile.low_cylinder	= SMART_LCYL_PASS;
+	taskfile.high_cylinder	= SMART_HCYL_PASS;
+	taskfile.command	= WIN_SMART;
 	(void) smart_enable(drive);
-	return ide_wait_cmd(drive, WIN_SMART, 0, SMART_READ_THRESHOLDS, 1, buf);
+	return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
 }
 
 static int proc_idedisk_read_cache
@@ -615,7 +773,7 @@
 	int		len = 0, i = 0;
 
 	if (!get_smart_thresholds(drive, page)) {
-		unsigned short *val = ((unsigned short *)page) + 2;
+		unsigned short *val = (unsigned short *) page;
 		char *out = ((char *)val) + (SECTOR_WORDS * 4);
 		page = out;
 		do {
@@ -634,7 +792,7 @@
 	int		len = 0, i = 0;
 
 	if (!get_smart_values(drive, page)) {
-		unsigned short *val = ((unsigned short *)page) + 2;
+		unsigned short *val = (unsigned short *) page;
 		char *out = ((char *)val) + (SECTOR_WORDS * 4);
 		page = out;
 		do {
@@ -660,6 +818,10 @@
 
 #endif	/* CONFIG_PROC_FS */
 
+/*
+ * This is tightly woven into the driver->do_special can not touch.
+ * DON'T do it again until a total personality rewrite is committed.
+ */
 static int set_multcount(ide_drive_t *drive, int arg)
 {
 	struct request rq;
@@ -683,6 +845,79 @@
 	return 0;
 }
 
+static int write_cache (ide_drive_t *drive, int arg)
+{
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+	taskfile.feature	= (arg) ? SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;
+	taskfile.command	= WIN_SETFEATURES;
+
+	if (!(drive->id->cfs_enable_2 & 0x3000))
+		return 1;
+
+	(void) ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+	drive->wcache = arg;
+	return 0;
+}
+
+static int do_idedisk_standby (ide_drive_t *drive)
+{
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+	taskfile.command	= WIN_STANDBYNOW1;
+	return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+}
+
+static int do_idedisk_flushcache (ide_drive_t *drive)
+{
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+	if (drive->id->cfs_enable_2 & 0x2400) {
+		taskfile.command	= WIN_FLUSH_CACHE_EXT;
+	} else {
+		taskfile.command	= WIN_FLUSH_CACHE;
+	}
+	return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+}
+
+static int set_acoustic (ide_drive_t *drive, int arg)
+{
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+
+	taskfile.feature	= (arg)?SETFEATURES_EN_AAM:SETFEATURES_DIS_AAM;
+	taskfile.sector_count	= arg;
+
+	taskfile.command	= WIN_SETFEATURES;
+	(void) ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+	drive->acoustic = arg;
+	return 0;
+}
+
+static int probe_lba_addressing (ide_drive_t *drive, int arg)
+{
+	drive->addressing =  0;
+
+	if (!(drive->id->cfs_enable_2 & 0x0400))
+                return -EIO;
+
+	drive->addressing = arg;
+	return 0;
+}
+
+static int set_lba_addressing (ide_drive_t *drive, int arg)
+{
+	return (probe_lba_addressing(drive, arg));
+}
+
 static void idedisk_add_settings(ide_drive_t *drive)
 {
 	struct hd_driveid *id = drive->id;
@@ -692,12 +927,15 @@
 	ide_add_setting(drive,	"bios_cyl",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->bios_cyl,		NULL);
 	ide_add_setting(drive,	"bios_head",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	255,				1,	1,	&drive->bios_head,		NULL);
 	ide_add_setting(drive,	"bios_sect",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	63,				1,	1,	&drive->bios_sect,		NULL);
+	ide_add_setting(drive,	"address",		SETTING_RW,					HDIO_GET_ADDRESS,	HDIO_SET_ADDRESS,	TYPE_INTA,	0,	2,				1,	1,	&drive->addressing,	set_lba_addressing);
 	ide_add_setting(drive,	"bswap",		SETTING_READ,					-1,			-1,			TYPE_BYTE,	0,	1,				1,	1,	&drive->bswap,			NULL);
-	ide_add_setting(drive,	"multcount",		id ? SETTING_RW : SETTING_READ,			HDIO_GET_MULTCOUNT,	HDIO_SET_MULTCOUNT,	TYPE_BYTE,	0,	id ? id->max_multsect : 0,	1,	2,	&drive->mult_count,		set_multcount);
+	ide_add_setting(drive,	"multcount",		id ? SETTING_RW : SETTING_READ,			HDIO_GET_MULTCOUNT,	HDIO_SET_MULTCOUNT,	TYPE_BYTE,	0,	id ? id->max_multsect : 0,	1,	1,	&drive->mult_count,		set_multcount);
 	ide_add_setting(drive,	"nowerr",		SETTING_RW,					HDIO_GET_NOWERR,	HDIO_SET_NOWERR,	TYPE_BYTE,	0,	1,				1,	1,	&drive->nowerr,			set_nowerr);
-	ide_add_setting(drive,	"breada_readahead",	SETTING_RW,					BLKRAGET,		BLKRASET,		TYPE_INT,	0,	255,				1,	2,	&read_ahead[major],		NULL);
+	ide_add_setting(drive,	"breada_readahead",	SETTING_RW,					BLKRAGET,		BLKRASET,		TYPE_INT,	0,	255,				1,	1,	&read_ahead[major],		NULL);
 	ide_add_setting(drive,	"file_readahead",	SETTING_RW,					BLKFRAGET,		BLKFRASET,		TYPE_INTA,	0,	4096,			PAGE_SIZE,	1024,	&max_readahead[major][minor],	NULL);
 	ide_add_setting(drive,	"lun",			SETTING_RW,					-1,			-1,			TYPE_INT,	0,	7,				1,	1,	&drive->lun,			NULL);
+	ide_add_setting(drive,	"wcache",		SETTING_RW,					HDIO_GET_WCACHE,	HDIO_SET_WCACHE,	TYPE_BYTE,	0,	1,				1,	1,	&drive->wcache,			write_cache);
+	ide_add_setting(drive,	"acoustic",		SETTING_RW,					HDIO_GET_ACOUSTIC,	HDIO_SET_ACOUSTIC,	TYPE_BYTE,	0,	254,				1,	1,	&drive->acoustic,		set_acoustic);
 	ide_add_setting(drive,	"failures",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->failures,		NULL);
 	ide_add_setting(drive,	"max_failures",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->max_failures,		NULL);
 }
@@ -769,7 +1007,6 @@
 	if ((capacity >= (drive->bios_cyl * drive->bios_sect * drive->bios_head)) &&
 	    (!drive->forced_geom) && drive->bios_sect && drive->bios_head)
 		drive->bios_cyl = (capacity / drive->bios_sect) / drive->bios_head;
-
 	printk (KERN_INFO "%s: %ld sectors", drive->name, capacity);
 
 	/* Give size in megabytes (MB), not mebibytes (MiB). */
@@ -801,21 +1038,25 @@
 			drive->mult_req = id->max_multsect;
 		if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect))
 			drive->special.b.set_multmode = 1;
-#endif
+#endif	/* CONFIG_IDEDISK_MULTI_MODE */
 	}
 	drive->no_io_32bit = id->dword_io ? 1 : 0;
-}
-
-static int idedisk_reinit (ide_drive_t *drive)
-{
-	return 0;
+	if (drive->id->cfs_enable_2 & 0x3000)
+		write_cache(drive, (id->cfs_enable_2 & 0x3000));
+	(void) probe_lba_addressing(drive, 1);
 }
 
 static int idedisk_cleanup (ide_drive_t *drive)
 {
+	if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
+		if (do_idedisk_flushcache(drive))
+			printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n",
+				drive->name);
 	return ide_unregister_subdriver(drive);
 }
 
+int idedisk_reinit(ide_drive_t *drive);
+
 /*
  *      IDE subdriver functions, registered with ide.c
  */
@@ -827,6 +1068,8 @@
 	supports_dma:		1,
 	supports_dsc_overlap:	0,
 	cleanup:		idedisk_cleanup,
+	standby:		do_idedisk_standby,
+	flushcache:		do_idedisk_flushcache,
 	do_request:		do_rw_disk,
 	end_request:		NULL,
 	ioctl:			NULL,
@@ -851,6 +1094,32 @@
 
 MODULE_DESCRIPTION("ATA DISK Driver");
 
+int idedisk_reinit (ide_drive_t *drive)
+{
+	int failed = 0;
+
+	MOD_INC_USE_COUNT;
+
+	if (ide_register_subdriver (drive, &idedisk_driver, IDE_SUBDRIVER_VERSION)) {
+		printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
+		return 1;
+	}
+	DRIVER(drive)->busy++;
+	idedisk_setup(drive);
+	if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
+		printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head);
+		(void) idedisk_cleanup(drive);
+		DRIVER(drive)->busy--;
+		return 1;
+	}
+	DRIVER(drive)->busy--;
+	failed--;
+
+	ide_register_module(&idedisk_module);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
 static void __exit idedisk_exit (void)
 {
 	ide_drive_t *drive;
@@ -882,12 +1151,15 @@
 			printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
 			continue;
 		}
+		DRIVER(drive)->busy++;
 		idedisk_setup(drive);
 		if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
 			printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head);
 			(void) idedisk_cleanup(drive);
+			DRIVER(drive)->busy--;
 			continue;
 		}
+		DRIVER(drive)->busy--;
 		failed--;
 	}
 	ide_register_module(&idedisk_module);
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/ide-dma.c linux/drivers/ide/ide-dma.c
--- v2.5.2/linux/drivers/ide/ide-dma.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/ide-dma.c	Tue Jan 15 11:27:30 2002
@@ -243,6 +243,44 @@
 	return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
 }
 
+static int ide_raw_build_sglist (ide_hwif_t *hwif, struct request *rq)
+{
+	struct scatterlist *sg = hwif->sg_table;
+	int nents = 0;
+	ide_task_t *args = rq->special;
+#if 1
+	unsigned char *virt_addr = rq->buffer;
+	int sector_count = rq->nr_sectors;
+#else
+        nents = blk_rq_map_sg(rq->q, rq, hwif->sg_table);
+
+	if (nents > rq->nr_segments)
+		printk("ide-dma: received %d segments, build %d\n", rq->nr_segments, nents);
+#endif
+
+	if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
+		hwif->sg_dma_direction = PCI_DMA_TODEVICE;
+	else
+		hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+
+#if 1	
+	if (sector_count > 128) {
+		memset(&sg[nents], 0, sizeof(*sg));
+		sg[nents].address = virt_addr;
+		sg[nents].length = 128  * SECTOR_SIZE;
+		nents++;
+		virt_addr = virt_addr + (128 * SECTOR_SIZE);
+		sector_count -= 128;
+	}
+	memset(&sg[nents], 0, sizeof(*sg));
+	sg[nents].address = virt_addr;
+	sg[nents].length =  sector_count  * SECTOR_SIZE;
+	nents++;
+ #endif
+
+	return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
+}
+
 /*
  * ide_build_dmatable() prepares a dma request.
  * Returns 0 if all went okay, returns 1 otherwise.
@@ -261,7 +299,11 @@
 	int i;
 	struct scatterlist *sg;
 
-	hwif->sg_nents = i = ide_build_sglist(hwif, HWGROUP(drive)->rq);
+	if (HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) {
+		hwif->sg_nents = i = ide_raw_build_sglist(hwif, HWGROUP(drive)->rq);
+	} else {
+		hwif->sg_nents = i = ide_build_sglist(hwif, HWGROUP(drive)->rq);
+	}
 	if (!i)
 		return 0;
 
@@ -387,7 +429,14 @@
 	struct hd_driveid *id = drive->id;
 
 	if ((id->field_valid & 4) && (eighty_ninty_three(drive)) &&
-	    (id->dma_ultra & (id->dma_ultra >> 11) & 7)) {
+	    (id->dma_ultra & (id->dma_ultra >> 14) & 3)) {
+		if ((id->dma_ultra >> 15) & 1) {
+			printk(", UDMA(mode 7)");	/* UDMA BIOS-enabled! */
+		} else {
+			printk(", UDMA(133)");	/* UDMA BIOS-enabled! */
+		}
+	} else if ((id->field_valid & 4) && (eighty_ninty_three(drive)) &&
+	  	  (id->dma_ultra & (id->dma_ultra >> 11) & 7)) {
 		if ((id->dma_ultra >> 13) & 1) {
 			printk(", UDMA(100)");	/* UDMA BIOS-enabled! */
 		} else if ((id->dma_ultra >> 12) & 1) {
@@ -414,14 +463,24 @@
 
 static int config_drive_for_dma (ide_drive_t *drive)
 {
+	int config_allows_dma = 1;
 	struct hd_driveid *id = drive->id;
 	ide_hwif_t *hwif = HWIF(drive);
 
-	if (id && (id->capability & 1) && hwif->autodma) {
+#ifdef CONFIG_IDEDMA_ONLYDISK
+	if (drive->media != ide_disk)
+		config_allows_dma = 0;
+#endif
+
+	if (id && (id->capability & 1) && hwif->autodma && config_allows_dma) {
 		/* Consult the list of known "bad" drives */
 		if (ide_dmaproc(ide_dma_bad_drive, drive))
 			return hwif->dmaproc(ide_dma_off, drive);
 
+		/* Enable DMA on any drive that has UltraDMA (mode 6/7/?) enabled */
+		if ((id->field_valid & 4) && (eighty_ninty_three(drive)))
+			if ((id->dma_ultra & (id->dma_ultra >> 14) & 2))
+				return hwif->dmaproc(ide_dma_on, drive);
 		/* Enable DMA on any drive that has UltraDMA (mode 3/4/5) enabled */
 		if ((id->field_valid & 4) && (eighty_ninty_three(drive)))
 			if ((id->dma_ultra & (id->dma_ultra >> 11) & 7))
@@ -453,7 +512,7 @@
 	printk("%s: dma_timer_expiry: dma status == 0x%02x\n", drive->name, dma_stat);
 #endif /* DEBUG */
 
-#if 1
+#if 0
 	HWGROUP(drive)->expiry = NULL;	/* one free ride for now */
 #endif
 
@@ -474,10 +533,10 @@
 	unsigned long flags;
 	ide_startstop_t startstop;
 
-	spin_lock_irqsave(&io_request_lock, flags);
+	spin_lock_irqsave(&ide_lock, flags);
 	hwgroup->handler = NULL;
 	del_timer(&hwgroup->timer);
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	spin_unlock_irqrestore(&ide_lock, flags);
 
 	drive->waiting_for_dma = 0;
 
@@ -555,11 +614,20 @@
 			if (drive->media != ide_disk)
 				return 0;
 #ifdef CONFIG_BLK_DEV_IDEDMA_TIMEOUT
-			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);	/* issue cmd to drive */
+			ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, NULL);	/* issue cmd to drive */
 #else /* !CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
 			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, dma_timer_expiry);	/* issue cmd to drive */
 #endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
-			OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+			if ((HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) &&
+			    (drive->addressing == 1)) {
+				ide_task_t *args = HWGROUP(drive)->rq->special;
+				OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
+			} else if (drive->addressing) {
+				OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
+			} else {
+				OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+			}
+			return HWIF(drive)->dmaproc(ide_dma_begin, drive);
 		case ide_dma_begin:
 			/* Note that this is done *after* the cmd has
 			 * been issued to the drive, as per the BM-IDE spec.
@@ -577,7 +645,7 @@
 			return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;	/* verify good DMA status */
 		case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */
 			dma_stat = inb(dma_base+2);
-#if 0	/* do not set unless you know what you are doing */
+#if 0  /* do not set unless you know what you are doing */
 			if (dma_stat & 4) {
 				byte stat = GET_STAT();
 				outb(dma_base+2, dma_stat & 0xE4);
@@ -622,6 +690,8 @@
 				GET_STAT(), dma_stat);
 
 			return restart_request(drive);  // BUG: return types do not match!!
+//#else
+//			return HWGROUP(drive)->handler(drive);
 #endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
 		case ide_dma_retune:
 		case ide_dma_lostirq:
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/ide-features.c linux/drivers/ide/ide-features.c
--- v2.5.2/linux/drivers/ide/ide-features.c	Fri Feb  9 11:40:02 2001
+++ linux/drivers/ide/ide-features.c	Tue Jan 15 11:27:30 2002
@@ -127,30 +127,14 @@
 		case XFER_UDMA_3:	return XFER_UDMA_2;
 		case XFER_UDMA_2:	return XFER_UDMA_1;
 		case XFER_UDMA_1:	return XFER_UDMA_0;
+			/*
+			 * OOPS we do not goto non Ultra DMA modes
+			 * without iCRC's available we force
+			 * the system to PIO and make the user
+			 * invoke the ATA-1 ATA-2 DMA modes.
+			 */
 		case XFER_UDMA_0:
-			if (drive->id->dma_mword & 0x0004) return XFER_MW_DMA_2;
-			else if (drive->id->dma_mword & 0x0002) return XFER_MW_DMA_1;
-			else if (drive->id->dma_mword & 0x0001) return XFER_MW_DMA_0;
-			else return XFER_PIO_4;
-		case XFER_MW_DMA_2:	return XFER_MW_DMA_1;
-		case XFER_MW_DMA_1:	return XFER_MW_DMA_0;
-		case XFER_MW_DMA_0:
-			if (drive->id->dma_1word & 0x0004) return XFER_SW_DMA_2;
-			else if (drive->id->dma_1word & 0x0002) return XFER_SW_DMA_1;
-			else if (drive->id->dma_1word & 0x0001) return XFER_SW_DMA_0;
-			else return XFER_PIO_4;
-		case XFER_SW_DMA_2:	return XFER_SW_DMA_1;
-		case XFER_SW_DMA_1:	return XFER_SW_DMA_0;
-		case XFER_SW_DMA_0:
-			{
-				return XFER_PIO_4;
-			}
-		case XFER_PIO_4:	return XFER_PIO_3;
-		case XFER_PIO_3:	return XFER_PIO_2;
-		case XFER_PIO_2:	return XFER_PIO_1;
-		case XFER_PIO_1:	return XFER_PIO_0;
-		case XFER_PIO_0:
-		default:		return XFER_PIO_SLOW;
+		default:		return XFER_PIO_4;
 	}
 }
 
@@ -193,7 +177,7 @@
 		__restore_flags(flags);	/* local CPU only */
 		return 0;
 	}
-	ide_input_data(drive, id, SECTOR_WORDS);
+	ata_input_data(drive, id, SECTOR_WORDS);
 	(void) GET_STAT();	/* clear drive IRQ */
 	ide__sti();		/* local CPU only */
 	__restore_flags(flags);	/* local CPU only */
@@ -216,11 +200,11 @@
  * in combination with the device (usually a disk) properly detect
  * and acknowledge each end of the ribbon.
  */
-int ide_ata66_check (ide_drive_t *drive, byte cmd, byte nsect, byte feature)
+int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
 {
-	if ((cmd == WIN_SETFEATURES) &&
-	    (nsect > XFER_UDMA_2) &&
-	    (feature == SETFEATURES_XFER)) {
+	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
+	    (args->tfRegister[IDE_SECTOR_OFFSET] > XFER_UDMA_2) &&
+	    (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER)) {
 		if (!HWIF(drive)->udma_four) {
 			printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n", HWIF(drive)->name);
 			return 1;
@@ -243,11 +227,11 @@
  * 1 : Safe to update drive->id DMA registers.
  * 0 : OOPs not allowed.
  */
-int set_transfer (ide_drive_t *drive, byte cmd, byte nsect, byte feature)
+int set_transfer (ide_drive_t *drive, ide_task_t *args)
 {
-	if ((cmd == WIN_SETFEATURES) &&
-	    (nsect >= XFER_SW_DMA_0) &&
-	    (feature == SETFEATURES_XFER) &&
+	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
+	    (args->tfRegister[IDE_SECTOR_OFFSET] >= XFER_SW_DMA_0) &&
+	    (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER) &&
 	    (drive->id->dma_ultra ||
 	     drive->id->dma_mword ||
 	     drive->id->dma_1word))
@@ -389,3 +373,4 @@
 EXPORT_SYMBOL(set_transfer);
 EXPORT_SYMBOL(eighty_ninty_three);
 EXPORT_SYMBOL(ide_config_drive_speed);
+
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/ide-floppy.c linux/drivers/ide/ide-floppy.c
--- v2.5.2/linux/drivers/ide/ide-floppy.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/ide/ide-floppy.c	Tue Jan 15 12:32:36 2002
@@ -71,9 +71,14 @@
  *                       including set_bit patch from Rusty Russel
  * Ver 0.97  Jul 22 01   Merge 0.91-0.96 onto 0.9.sv for ac series
  * Ver 0.97.sv Aug 3 01  Backported from 2.4.7-ac3
+ * Ver 0.98  Oct 26 01   Split idefloppy_transfer_pc into two pieces to
+ *                        fix a lost interrupt problem. It appears the busy
+ *                        bit was being deasserted by my IOMEGA ATAPI ZIP 100
+ *                        drive before the drive was actually ready.
+ * Ver 0.98a Oct 29 01   Expose delay value so we can play.
  */
 
-#define IDEFLOPPY_VERSION "0.97.sv"
+#define IDEFLOPPY_VERSION "0.98a"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -276,6 +281,7 @@
 	 *	Last error information
 	 */
 	byte sense_key, asc, ascq;
+	byte ticks;		/* delay this long before sending packet command */
 	int progress_indication;
 
 	/*
@@ -289,6 +295,8 @@
 	unsigned long flags;			/* Status/Action flags */
 } idefloppy_floppy_t;
 
+#define IDEFLOPPY_TICKS_DELAY	3	/* default delay for ZIP 100 */
+
 /*
  *	Floppy flag bits values.
  */
@@ -297,7 +305,7 @@
 #define IDEFLOPPY_USE_READ12		2	/* Use READ12/WRITE12 or READ10/WRITE10 */
 #define	IDEFLOPPY_FORMAT_IN_PROGRESS	3	/* Format in progress */
 #define IDEFLOPPY_CLIK_DRIVE	        4       /* Avoid commands not supported in Clik drive */
-
+#define IDEFLOPPY_ZIP_DRIVE		5	/* Requires BH algorithm for packets */
 
 /*
  *	ATAPI floppy drive packet commands
@@ -680,7 +688,7 @@
 	/* Why does this happen? */
 	if (!rq)
 		return;
-	if (rq->flags & IDEFLOPPY_RQ) {
+	if (!(rq->flags & IDEFLOPPY_RQ)) {
 		ide_end_request (uptodate, hwgroup);
 		return;
 	}
@@ -985,6 +993,11 @@
 	return ide_started;
 }
 
+/*
+ * This is the original routine that did the packet transfer.
+ * It fails at high speeds on the Iomega ZIP drive, so there's a slower version
+ * for that drive below. The algorithm is chosen based on drive type
+ */
 static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive)
 {
 	ide_startstop_t startstop;
@@ -1005,6 +1018,56 @@
 	return ide_started;
 }
 
+
+/*
+ * What we have here is a classic case of a top half / bottom half
+ * interrupt service routine. In interrupt mode, the device sends
+ * an interrupt to signal it's ready to receive a packet. However,
+ * we need to delay about 2-3 ticks before issuing the packet or we
+ * gets in trouble.
+ *
+ * So, follow carefully. transfer_pc1 is called as an interrupt (or
+ * directly). In either case, when the device says it's ready for a 
+ * packet, we schedule the packet transfer to occur about 2-3 ticks
+ * later in transfer_pc2.
+ */
+static int idefloppy_transfer_pc2 (ide_drive_t *drive)
+{
+	idefloppy_floppy_t *floppy = drive->driver_data;
+
+	atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */
+	return IDEFLOPPY_WAIT_CMD;		/* Timeout for the packet command */
+}
+
+static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive)
+{
+	idefloppy_floppy_t *floppy = drive->driver_data;
+	ide_startstop_t startstop;
+	idefloppy_ireason_reg_t ireason;
+
+	if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
+		printk (KERN_ERR "ide-floppy: Strange, packet command initiated yet DRQ isn't asserted\n");
+		return startstop;
+	}
+	ireason.all=IN_BYTE (IDE_IREASON_REG);
+	if (!ireason.b.cod || ireason.b.io) {
+		printk (KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while issuing a packet command\n");
+		return ide_do_reset (drive);
+	}
+	/* 
+	 * The following delay solves a problem with ATAPI Zip 100 drives where the
+	 * Busy flag was apparently being deasserted before the unit was ready to
+	 * receive data. This was happening on a 1200 MHz Athlon system. 10/26/01
+	 * 25msec is too short, 40 and 50msec work well. idefloppy_pc_intr will 
+	 * not be actually used until after the packet is moved in about 50 msec.
+	 */
+	ide_set_handler (drive, 
+	  &idefloppy_pc_intr, 		/* service routine for packet command */
+	  floppy->ticks,			/* wait this long before "failing" */
+	  &idefloppy_transfer_pc2);	/* fail == transfer_pc2 */
+	return ide_started;
+}
+
 /*
  *	Issue a packet command
  */
@@ -1013,6 +1076,7 @@
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	idefloppy_bcount_reg_t bcount;
 	int dma_ok = 0;
+	ide_handler_t *pkt_xfer_routine;
 
 #if IDEFLOPPY_DEBUG_BUGS
 	if (floppy->pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD && pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
@@ -1072,13 +1136,20 @@
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
+	/* Can we transfer the packet when we get the interrupt or wait? */
+	if (test_bit (IDEFLOPPY_ZIP_DRIVE, &floppy->flags)) {
+		pkt_xfer_routine = &idefloppy_transfer_pc1;	/* wait */
+	} else {
+		pkt_xfer_routine = &idefloppy_transfer_pc;	/* immediate */
+	}
+	
 	if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) {
-		ide_set_handler (drive, &idefloppy_transfer_pc, IDEFLOPPY_WAIT_CMD, NULL);
+		ide_set_handler (drive, pkt_xfer_routine, IDEFLOPPY_WAIT_CMD, NULL);
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);		/* Issue the packet command */
 		return ide_started;
 	} else {
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
-		return idefloppy_transfer_pc (drive);
+		return (*pkt_xfer_routine) (drive);
 	}
 }
 
@@ -1979,10 +2050,7 @@
 
 #endif	/* CONFIG_PROC_FS */
 
-static int idefloppy_reinit (ide_drive_t *drive)
-{
-	return 0;
-}
+int idefloppy_reinit(ide_drive_t *drive);
 
 /*
  *	IDE subdriver functions, registered with ide.c
@@ -1995,6 +2063,8 @@
 	supports_dma:		1,
 	supports_dsc_overlap:	0,
 	cleanup:		idefloppy_cleanup,
+	standby:		NULL,
+	flushcache:		NULL,
 	do_request:		idefloppy_do_request,
 	end_request:		idefloppy_end_request,
 	ioctl:			idefloppy_ioctl,
@@ -2017,6 +2087,40 @@
 	NULL
 };
 
+int idefloppy_reinit (ide_drive_t *drive)
+{
+	idefloppy_floppy_t *floppy;
+	int failed = 0;
+
+	MOD_INC_USE_COUNT;
+	while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, NULL, failed++)) != NULL) {
+		if (!idefloppy_identify_device (drive, drive->id)) {
+			printk (KERN_ERR "ide-floppy: %s: not supported by this version of ide-floppy\n", drive->name);
+			continue;
+		}
+		if (drive->scsi) {
+			printk("ide-floppy: passing drive %s to ide-scsi emulation.\n", drive->name);
+			continue;
+		}
+		if ((floppy = (idefloppy_floppy_t *) kmalloc (sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) {
+			printk (KERN_ERR "ide-floppy: %s: Can't allocate a floppy structure\n", drive->name);
+			continue;
+		}
+		if (ide_register_subdriver (drive, &idefloppy_driver, IDE_SUBDRIVER_VERSION)) {
+			printk (KERN_ERR "ide-floppy: %s: Failed to register the driver with ide.c\n", drive->name);
+			kfree (floppy);
+			continue;
+		}
+		DRIVER(drive)->busy++;
+		idefloppy_setup (drive, floppy);
+		DRIVER(drive)->busy--;
+		failed--;
+	}
+	ide_register_module(&idefloppy_module);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
 MODULE_DESCRIPTION("ATAPI FLOPPY Driver");
 
 static void __exit idefloppy_exit (void)
@@ -2069,7 +2173,9 @@
 			kfree (floppy);
 			continue;
 		}
+		DRIVER(drive)->busy++;
 		idefloppy_setup (drive, floppy);
+		DRIVER(drive)->busy--;
 		failed--;
 	}
 	ide_register_module(&idefloppy_module);
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/ide-geometry.c linux/drivers/ide/ide-geometry.c
--- v2.5.2/linux/drivers/ide/ide-geometry.c	Fri Nov  9 14:23:34 2001
+++ linux/drivers/ide/ide-geometry.c	Tue Jan 15 11:27:30 2002
@@ -6,6 +6,8 @@
 #include <linux/mc146818rtc.h>
 #include <asm/io.h>
 
+#ifdef CONFIG_BLK_DEV_IDE
+
 /*
  * We query CMOS about hard disks : it could be that we have a SCSI/ESDI/etc
  * controller that is BIOS compatible with ST-506, and thus showing up in our
@@ -40,7 +42,11 @@
  * Consequently, also the former "drive->present = 1" below was a mistake.
  *
  * Eventually the entire routine below should be removed.
+ *
+ * 17-OCT-2000 rjohnson@analogic.com Added spin-locks for reading CMOS
+ * chip.
  */
+
 void probe_cmos_for_drives (ide_hwif_t *hwif)
 {
 #ifdef __i386__
@@ -80,9 +86,10 @@
 	}
 #endif
 }
+#endif /* CONFIG_BLK_DEV_IDE */
 
 
-#ifdef CONFIG_BLK_DEV_IDE
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 
 extern ide_drive_t * get_info_ptr(kdev_t);
 extern unsigned long current_capacity (ide_drive_t *);
@@ -214,4 +221,4 @@
 		       drive->bios_cyl, drive->bios_head, drive->bios_sect);
 	return ret;
 }
-#endif /* CONFIG_BLK_DEV_IDE */
+#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/ide-pci.c linux/drivers/ide/ide-pci.c
--- v2.5.2/linux/drivers/ide/ide-pci.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/ide-pci.c	Tue Jan 15 11:27:30 2002
@@ -12,6 +12,13 @@
  *  configuration of all PCI IDE interfaces present in a system.  
  */
 
+/*
+ * Chipsets that are on the IDE_IGNORE list because of problems of not being
+ * set at compile time.
+ *
+ * CONFIG_BLK_DEV_PDC202XX
+ */
+
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -47,6 +54,8 @@
 #define DEVID_PDC20267	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267})
 #define DEVID_PDC20268  ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268})
 #define DEVID_PDC20268R ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268R})
+#define DEVID_PDC20269	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269})
+#define DEVID_PDC20275	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275})
 #define DEVID_RZ1000	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_RZ1000})
 #define DEVID_RZ1001	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_RZ1001})
 #define DEVID_SAMURAI	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_SAMURAI_IDE})
@@ -55,6 +64,7 @@
 #define DEVID_CMD646	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_646})
 #define DEVID_CMD648	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_648})
 #define DEVID_CMD649	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_649})
+#define DEVID_CMD680	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_680})
 #define DEVID_SIS5513	((ide_pci_devid_t){PCI_VENDOR_ID_SI,      PCI_DEVICE_ID_SI_5513})
 #define DEVID_OPTI621	((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    PCI_DEVICE_ID_OPTI_82C621})
 #define DEVID_OPTI621V	((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    PCI_DEVICE_ID_OPTI_82C558})
@@ -87,6 +97,7 @@
 #define DEVID_ITE8172G	((ide_pci_devid_t){PCI_VENDOR_ID_ITE,     PCI_DEVICE_ID_ITE_IT8172G})
 
 #define	IDE_IGNORE	((void *)-1)
+#define IDE_NO_DRIVER	((void *)-2)
 
 #ifdef CONFIG_BLK_DEV_AEC62XX
 extern unsigned int pci_init_aec62xx(struct pci_dev *, const char *);
@@ -100,7 +111,7 @@
 #else
 #define PCI_AEC62XX	NULL
 #define ATA66_AEC62XX	NULL
-#define INIT_AEC62XX	NULL
+#define INIT_AEC62XX	IDE_NO_DRIVER
 #define DMA_AEC62XX	NULL
 #endif
 
@@ -116,7 +127,7 @@
 #else
 #define PCI_ALI15X3	NULL
 #define ATA66_ALI15X3	NULL
-#define INIT_ALI15X3	NULL
+#define INIT_ALI15X3	IDE_NO_DRIVER
 #define DMA_ALI15X3	NULL
 #endif
 
@@ -132,7 +143,7 @@
 #else
 #define PCI_AMD74XX	NULL
 #define ATA66_AMD74XX	NULL
-#define INIT_AMD74XX	NULL
+#define INIT_AMD74XX	IDE_NO_DRIVER
 #define DMA_AMD74XX	NULL
 #endif
 
@@ -150,7 +161,7 @@
 #ifdef __sparc_v9__
 #define INIT_CMD64X	IDE_IGNORE
 #else
-#define INIT_CMD64X	NULL
+#define INIT_CMD64X	IDE_NO_DRIVER
 #endif
 #endif
 
@@ -161,7 +172,7 @@
 #define INIT_CY82C693	&ide_init_cy82c693
 #else
 #define PCI_CY82C693	NULL
-#define INIT_CY82C693	NULL
+#define INIT_CY82C693	IDE_NO_DRIVER
 #endif
 
 #ifdef CONFIG_BLK_DEV_CS5530
@@ -171,7 +182,7 @@
 #define INIT_CS5530	&ide_init_cs5530
 #else
 #define PCI_CS5530	NULL
-#define INIT_CS5530	NULL
+#define INIT_CS5530	IDE_NO_DRIVER
 #endif
 
 #ifdef CONFIG_BLK_DEV_HPT34X
@@ -200,7 +211,7 @@
 static byte hpt363_shared_pin;
 #define PCI_HPT366	NULL
 #define ATA66_HPT366	NULL
-#define INIT_HPT366	NULL
+#define INIT_HPT366	IDE_NO_DRIVER
 #define DMA_HPT366	NULL
 #endif
 
@@ -215,7 +226,7 @@
 extern void ide_init_opti621(ide_hwif_t *);
 #define INIT_OPTI621	&ide_init_opti621
 #else
-#define INIT_OPTI621	NULL
+#define INIT_OPTI621	IDE_NO_DRIVER
 #endif
 
 #ifdef CONFIG_BLK_DEV_PDC_ADMA
@@ -242,9 +253,9 @@
 #define ATA66_PDC202XX	&ata66_pdc202xx
 #define INIT_PDC202XX	&ide_init_pdc202xx
 #else
-#define PCI_PDC202XX	NULL
-#define ATA66_PDC202XX	NULL
-#define INIT_PDC202XX	NULL
+#define PCI_PDC202XX	IDE_IGNORE
+#define ATA66_PDC202XX	IDE_IGNORE
+#define INIT_PDC202XX	IDE_IGNORE
 #endif
 
 #ifdef CONFIG_BLK_DEV_PIIX
@@ -257,7 +268,7 @@
 #else
 #define PCI_PIIX	NULL
 #define ATA66_PIIX	NULL
-#define INIT_PIIX	NULL
+#define INIT_PIIX	IDE_NO_DRIVER
 #endif
 
 #ifdef CONFIG_BLK_DEV_IT8172
@@ -269,7 +280,7 @@
 #else
 #define PCI_IT8172	NULL
 #define ATA66_IT8172	NULL
-#define INIT_IT8172	NULL
+#define INIT_IT8172	IDE_NO_DRIVER
 #endif
 
 #ifdef CONFIG_BLK_DEV_RZ1000
@@ -291,7 +302,7 @@
 #else
 #define PCI_SVWKS	NULL
 #define ATA66_SVWKS	NULL
-#define INIT_SVWKS	NULL
+#define INIT_SVWKS	IDE_NO_DRIVER
 #endif
 
 #ifdef CONFIG_BLK_DEV_SIS5513
@@ -304,7 +315,7 @@
 #else
 #define PCI_SIS5513	NULL
 #define ATA66_SIS5513	NULL
-#define INIT_SIS5513	NULL
+#define INIT_SIS5513	IDE_NO_DRIVER
 #endif
 
 #ifdef CONFIG_BLK_DEV_SLC90E66
@@ -317,7 +328,7 @@
 #else
 #define PCI_SLC90E66	NULL
 #define ATA66_SLC90E66	NULL
-#define INIT_SLC90E66	NULL
+#define INIT_SLC90E66	IDE_NO_DRIVER
 #endif
 
 #ifdef CONFIG_BLK_DEV_SL82C105
@@ -352,7 +363,7 @@
 #else
 #define PCI_VIA82CXXX	NULL
 #define ATA66_VIA82CXXX	NULL
-#define INIT_VIA82CXXX	NULL
+#define INIT_VIA82CXXX	IDE_NO_DRIVER
 #define DMA_VIA82CXXX	NULL
 #endif
 
@@ -394,7 +405,7 @@
 #ifdef CONFIG_PDC202XX_FORCE
         {DEVID_PDC20246,"PDC20246",	PCI_PDC202XX,	NULL,		INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	16 },
         {DEVID_PDC20262,"PDC20262",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48 },
-        {DEVID_PDC20265,"PDC20265",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48 },
+        {DEVID_PDC20265,"PDC20265",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	48 },
         {DEVID_PDC20267,"PDC20267",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48 },
 #else /* !CONFIG_PDC202XX_FORCE */
 	{DEVID_PDC20246,"PDC20246",	PCI_PDC202XX,	NULL,		INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}}, 	OFF_BOARD,	16 },
@@ -402,11 +413,13 @@
 	{DEVID_PDC20265,"PDC20265",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48 },
 	{DEVID_PDC20267,"PDC20267",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48 },
 #endif
-	{DEVID_PDC20268,"PDC20268",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	16 },
+	{DEVID_PDC20268,"PDC20268",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
 	/* Promise used a different PCI ident for the raid card apparently to try and
 	   prevent Linux detecting it and using our own raid code. We want to detect
 	   it for the ataraid drivers, so we have to list both here.. */
-	{DEVID_PDC20268R,"PDC20268",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	16 },
+	{DEVID_PDC20268R,"PDC20270",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
+	{DEVID_PDC20269,"PDC20269",	PCI_PDC202XX,	ATA66_PDC202XX,	 INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
+	{DEVID_PDC20275,"PDC20275",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
 	{DEVID_RZ1000,	"RZ1000",	NULL,		NULL,		INIT_RZ1000,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
 	{DEVID_RZ1001,	"RZ1001",	NULL,		NULL,		INIT_RZ1000,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
 	{DEVID_SAMURAI,	"SAMURAI",	NULL,		NULL,		INIT_SAMURAI,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
@@ -417,6 +430,7 @@
 	{DEVID_CMD646,	"CMD646",	PCI_CMD64X,	NULL,		INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x51,0x80,0x80}}, 	ON_BOARD,	0 },
 	{DEVID_CMD648,	"CMD648",	PCI_CMD64X,	ATA66_CMD64X,	INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
 	{DEVID_CMD649,	"CMD649",	PCI_CMD64X,	ATA66_CMD64X,	INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+	{DEVID_CMD680,	"CMD680",	PCI_CMD64X,	ATA66_CMD64X,	INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
 	{DEVID_HT6565,	"HT6565",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
 	{DEVID_OPTI621,	"OPTI621",	NULL,		NULL,		INIT_OPTI621,	NULL,		{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0 },
 	{DEVID_OPTI621X,"OPTI621X",	NULL,		NULL,		INIT_OPTI621,	NULL,		{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0 },
@@ -435,10 +449,10 @@
 	{DEVID_CY82C693,"CY82C693",	PCI_CY82C693,	NULL,		INIT_CY82C693,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
 	{DEVID_HINT,	"HINT_IDE",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
 	{DEVID_CS5530,	"CS5530",	PCI_CS5530,	NULL,		INIT_CS5530,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_AMD7401,	"AMD7401",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
+	{DEVID_AMD7401,	"AMD7401",	NULL,		NULL,		NULL,		DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
 	{DEVID_AMD7409,	"AMD7409",	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
 	{DEVID_AMD7411,	"AMD7411",	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
-	{DEVID_AMD7441, "AMD7441",	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
+	{DEVID_AMD7441,	"AMD7441",	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
 	{DEVID_PDCADMA,	"PDCADMA",	PCI_PDCADMA,	ATA66_PDCADMA,	INIT_PDCADMA,	DMA_PDCADMA,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
 	{DEVID_SLC90E66,"SLC90E66",	PCI_SLC90E66,	ATA66_SLC90E66,	INIT_SLC90E66,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
         {DEVID_OSB4,    "ServerWorks OSB4",		PCI_SVWKS,	ATA66_SVWKS,	INIT_SVWKS,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
@@ -460,6 +474,9 @@
 		case PCI_DEVICE_ID_PROMISE_20265:
 		case PCI_DEVICE_ID_PROMISE_20267:
 		case PCI_DEVICE_ID_PROMISE_20268:
+		case PCI_DEVICE_ID_PROMISE_20268R:
+		case PCI_DEVICE_ID_PROMISE_20269:
+		case PCI_DEVICE_ID_PROMISE_20275:
 		case PCI_DEVICE_ID_ARTOP_ATP850UF:
 		case PCI_DEVICE_ID_ARTOP_ATP860:
 		case PCI_DEVICE_ID_ARTOP_ATP860R:
@@ -594,7 +611,15 @@
 		autodma = 1;
 #endif
 
-	pci_enable_device(dev);
+	if (d->init_hwif == IDE_NO_DRIVER) {
+		printk(KERN_WARNING "%s: detected chipset, but driver not compiled in!\n", d->name);
+		d->init_hwif = NULL;
+	}
+
+	if (pci_enable_device(dev)) {
+		printk(KERN_WARNING "%s: (ide_setup_pci_device:) Could not enable device.\n", d->name);
+		return;
+	}
 
 check_if_enabled:
 	if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) {
@@ -754,7 +779,8 @@
 		}
 		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_MPIIX))
 			goto bypass_piix_dma;
-
+		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDCADMA))
+			goto bypass_legacy_dma;
 		if (hwif->udma_four) {
 			printk("%s: ATA-66/100 forced bit set (WARNING)!!\n", d->name);
 		} else {
@@ -771,12 +797,15 @@
 			autodma = 0;
 		if (autodma)
 			hwif->autodma = 1;
+
 		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20267) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268R) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20269) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20275) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260R) ||
@@ -787,6 +816,7 @@
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD646) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD648) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD649) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD680) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_OSB4) ||
 		    ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))) {
 			unsigned long dma_base = ide_get_or_set_dma_base(hwif, (!mate && d->extra) ? d->extra : 0, d->name);
@@ -813,6 +843,7 @@
 			}
 		}
 #endif	/* CONFIG_BLK_DEV_IDEDMA */
+bypass_legacy_dma:
 bypass_piix_dma:
 bypass_umc_dma:
 		if (d->init_hwif)  /* Call chipset-specific routine for each enabled hwif */
@@ -824,6 +855,44 @@
 		printk("%s: neither IDE port enabled (BIOS)\n", d->name);
 }
 
+static void __init pdc20270_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	struct pci_dev *dev2 = NULL, *findev;
+	ide_pci_device_t *d2;
+
+	if ((dev->bus->self &&
+	     dev->bus->self->vendor == PCI_VENDOR_ID_DEC) &&
+	    (dev->bus->self->device == PCI_DEVICE_ID_DEC_21150)) {
+		if (PCI_SLOT(dev->devfn) & 2) {
+			return;
+		}
+		d->extra = 0;
+		pci_for_each_dev(findev) {
+			if ((findev->vendor == dev->vendor) &&
+			    (findev->device == dev->device) &&
+			    (PCI_SLOT(findev->devfn) & 2)) {
+				byte irq = 0, irq2 = 0;
+				dev2 = findev;
+				pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+				pci_read_config_byte(dev2, PCI_INTERRUPT_LINE, &irq2);
+                                if (irq != irq2) {
+					dev2->irq = dev->irq;
+                                        pci_write_config_byte(dev2, PCI_INTERRUPT_LINE, irq);
+                                }
+
+			}
+		}
+	}
+
+	printk("%s: IDE controller on PCI bus %02x dev %02x\n", d->name, dev->bus->number, dev->devfn);
+	ide_setup_pci_device(dev, d);
+	if (!dev2)
+		return;
+	d2 = d;
+	printk("%s: IDE controller on PCI bus %02x dev %02x\n", d2->name, dev2->bus->number, dev2->devfn);
+	ide_setup_pci_device(dev2, d2);
+}
+
 static void __init hpt366_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d)
 {
 	struct pci_dev *dev2 = NULL, *findev;
@@ -904,6 +973,8 @@
 		return;	/* UM8886A/BF pair */
 	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366))
 		hpt366_device_order_fixup(dev, d);
+	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268R))
+		pdc20270_device_order_fixup(dev, d);
 	else if (!IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL) || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
 		if (IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL))
 			printk("%s: unknown IDE controller on PCI slot %s, VID=%04x, DID=%04x\n",
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/ide-pmac.c linux/drivers/ide/ide-pmac.c
--- v2.5.2/linux/drivers/ide/ide-pmac.c	Tue Oct  2 09:08:40 2001
+++ linux/drivers/ide/ide-pmac.c	Tue Jan 15 11:27:30 2002
@@ -1101,7 +1101,7 @@
 		HWGROUP(drive)->busy = 1;
 		pmac_ide_check_dma(drive);
 		HWGROUP(drive)->busy = 0;
-		spin_unlock_irq(&io_request_lock);
+		spin_unlock_irq(&ide_lock);
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
 }
@@ -1220,7 +1220,7 @@
 			/* Disable irq during sleep */
 			disable_irq(pmac_ide[i].irq);
 			if (unlock)
-				spin_unlock_irq(&io_request_lock);
+				spin_unlock_irq(&ide_lock);
 			
 			/* Check if this is a media bay with an IDE device or not
 			 * a media bay.
@@ -1279,11 +1279,11 @@
 			drive->using_dma = 0;
 
 			/* We resume processing on the HW group */
-			spin_lock_irqsave(&io_request_lock, flags);
+			spin_lock_irqsave(&ide_lock, flags);
 			enable_irq(pmac_ide[i].irq);
 			if (drive->present)
 				HWGROUP(drive)->busy = 0;
-			spin_unlock_irqrestore(&io_request_lock, flags);
+			spin_unlock_irqrestore(&ide_lock, flags);
 			
 			/* Wake the device
 			 * We could handle the slave here
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/ide-probe.c linux/drivers/ide/ide-probe.c
--- v2.5.2/linux/drivers/ide/ide-probe.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/ide/ide-probe.c	Tue Jan 15 11:27:30 2002
@@ -58,7 +58,22 @@
 	struct hd_driveid *id;
 
 	id = drive->id = kmalloc (SECTOR_WORDS*4, GFP_ATOMIC);	/* called with interrupts disabled! */
-	ide_input_data(drive, id, SECTOR_WORDS);		/* read 512 bytes of id info */
+	if (!id) {
+		printk(KERN_WARNING "(ide-probe::do_identify) Out of memory.\n");
+		goto err_kmalloc;
+	}
+	/* read 512 bytes of id info */
+#if 1
+	ata_input_data(drive, id, SECTOR_WORDS);		/* read 512 bytes of id info */
+#else
+        {
+                unsigned long   *ptr = (unsigned long *)id ;
+                unsigned long   lcount = 256/2 ;
+                // printk("IDE_DATA_REG = %#lx",IDE_DATA_REG);
+                while( lcount-- )
+                        *ptr++ = inl(IDE_DATA_REG);
+        }
+#endif
 	ide__sti();	/* local CPU only */
 	ide_fix_driveid(id);
 
@@ -76,8 +91,7 @@
 	if ((id->model[0] == 'P' && id->model[1] == 'M')
 	 || (id->model[0] == 'S' && id->model[1] == 'K')) {
 		printk("%s: EATA SCSI HBA %.10s\n", drive->name, id->model);
-		drive->present = 0;
-		return;
+		goto err_misc;
 	}
 #endif /* CONFIG_SCSI_EATA_DMA || CONFIG_SCSI_EATA_PIO */
 
@@ -96,7 +110,7 @@
 	ide_fixstring (id->serial_no, sizeof(id->serial_no), bswap);
 
 	if (strstr(id->model, "E X A B Y T E N E S T"))
-		return;
+		goto err_misc;
 
 	id->model[sizeof(id->model)-1] = '\0';	/* we depend on this a lot! */
 	printk("%s: %s, ", drive->name, id->model);
@@ -111,8 +125,7 @@
 #ifdef CONFIG_BLK_DEV_PDC4030
 		if (HWIF(drive)->channel == 1 && HWIF(drive)->chipset == ide_pdc4030) {
 			printk(" -- not supported on 2nd Promise port\n");
-			drive->present = 0;
-			return;
+			goto err_misc;
 		}
 #endif /* CONFIG_BLK_DEV_PDC4030 */
 		switch (type) {
@@ -174,6 +187,12 @@
 	printk("ATA DISK drive\n");
 	QUIRK_LIST(HWIF(drive),drive);
 	return;
+
+err_misc:
+	kfree(id);
+err_kmalloc:
+	drive->present = 0;
+	return;
 }
 
 /*
@@ -702,6 +721,10 @@
 #else /* !CONFIG_IDEPCI_SHARE_IRQ */
 		int sa = IDE_CHIPSET_IS_PCI(hwif->chipset) ? SA_INTERRUPT|SA_SHIRQ : SA_INTERRUPT;
 #endif /* CONFIG_IDEPCI_SHARE_IRQ */
+
+		if (hwif->io_ports[IDE_CONTROL_OFFSET])
+			OUT_BYTE(0x08, hwif->io_ports[IDE_CONTROL_OFFSET]); /* clear nIEN */
+
 		if (ide_request_irq(hwif->irq, &ide_intr, sa, hwif->name, hwgroup)) {
 			if (!match)
 				kfree(hwgroup);
@@ -769,17 +792,32 @@
 	int *bs, *max_ra;
 	extern devfs_handle_t ide_devfs_handle;
 
+#if 1
+	units = MAX_DRIVES;
+#else
 	/* figure out maximum drive number on the interface */
 	for (units = MAX_DRIVES; units > 0; --units) {
 		if (hwif->drives[units-1].present)
 			break;
 	}
+#endif
+
 	minors    = units * (1<<PARTN_BITS);
 	gd        = kmalloc (sizeof(struct gendisk), GFP_KERNEL);
+	if (!gd)
+		goto err_kmalloc_gd;
 	gd->sizes = kmalloc (minors * sizeof(int), GFP_KERNEL);
+	if (!gd->sizes)
+		goto err_kmalloc_gd_sizes;
 	gd->part  = kmalloc (minors * sizeof(struct hd_struct), GFP_KERNEL);
+	if (!gd->part)
+		goto err_kmalloc_gd_part;
 	bs        = kmalloc (minors*sizeof(int), GFP_KERNEL);
+	if (!bs)
+		goto err_kmalloc_bs;
 	max_ra    = kmalloc (minors*sizeof(int), GFP_KERNEL);
+	if (!max_ra)
+		goto err_kmalloc_max_ra;
 
 	memset(gd->part, 0, minors * sizeof(struct hd_struct));
 
@@ -811,6 +849,17 @@
 	add_gendisk(gd);
 
 	for (unit = 0; unit < units; ++unit) {
+#if 1
+		char name[64];
+		ide_add_generic_settings(hwif->drives + unit);
+		hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit);
+		sprintf (name, "host%d/bus%d/target%d/lun%d",
+			(hwif->channel && hwif->mate) ?
+			hwif->mate->index : hwif->index,
+			hwif->channel, unit, hwif->drives[unit].lun);
+		if (hwif->drives[unit].present)
+			hwif->drives[unit].de = devfs_mk_dir(ide_devfs_handle, name, NULL);
+#else
 		if (hwif->drives[unit].present) {
 			char name[64];
 
@@ -822,7 +871,21 @@
 			hwif->drives[unit].de =
 				devfs_mk_dir (ide_devfs_handle, name, NULL);
 		}
+#endif
 	}
+	return;
+
+err_kmalloc_max_ra:
+	kfree(bs);
+err_kmalloc_bs:
+	kfree(gd->part);
+err_kmalloc_gd_part:
+	kfree(gd->sizes);
+err_kmalloc_gd_sizes:
+	kfree(gd);
+err_kmalloc_gd:
+	printk(KERN_WARNING "(ide::init_gendisk) Out of memory\n");
+	return;
 }
 
 static int hwif_init (ide_hwif_t *hwif)
@@ -880,6 +943,19 @@
 	return hwif->present;
 }
 
+void export_ide_init_queue (ide_drive_t *drive)
+{
+	ide_init_queue(drive);
+}
+
+byte export_probe_for_drive (ide_drive_t *drive)
+{
+	return probe_for_drive(drive);
+}
+
+EXPORT_SYMBOL(export_ide_init_queue);
+EXPORT_SYMBOL(export_probe_for_drive);
+
 int ideprobe_init (void);
 static ide_module_t ideprobe_module = {
 	IDE_PROBE_MODULE,
@@ -913,6 +989,8 @@
 }
 
 #ifdef MODULE
+extern int (*ide_xlate_1024_hook)(kdev_t, int, int, const char *);
+
 int init_module (void)
 {
 	unsigned int index;
@@ -921,12 +999,14 @@
 		ide_unregister(index);
 	ideprobe_init();
 	create_proc_ide_interfaces();
+	ide_xlate_1024_hook = ide_xlate_1024;
 	return 0;
 }
 
 void cleanup_module (void)
 {
 	ide_probe = NULL;
+	ide_xlate_1024_hook = 0;
 }
 MODULE_LICENSE("GPL");
 #endif /* MODULE */
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/ide-proc.c linux/drivers/ide/ide-proc.c
--- v2.5.2/linux/drivers/ide/ide-proc.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/ide-proc.c	Tue Jan 15 11:27:30 2002
@@ -65,6 +65,7 @@
 #include <linux/mm.h>
 #include <linux/pci.h>
 #include <linux/ctype.h>
+#include <linux/hdreg.h>
 #include <linux/ide.h>
 
 #include <asm/io.h>
@@ -447,7 +448,15 @@
 
 static int proc_ide_get_identify(ide_drive_t *drive, byte *buf)
 {
-	return ide_wait_cmd(drive, (drive->media == ide_disk) ? WIN_IDENTIFY : WIN_PIDENTIFY, 0, 0, 1, buf);
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr hobfile;
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+
+	taskfile.sector_count = 0x01;
+	taskfile.command = (drive->media == ide_disk) ? WIN_IDENTIFY : WIN_PIDENTIFY ;
+
+	return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
 }
 
 static int proc_ide_read_identify
@@ -457,7 +466,7 @@
 	int		len = 0, i = 0;
 
 	if (drive && !proc_ide_get_identify(drive, page)) {
-		unsigned short *val = ((unsigned short *)page) + 2;
+		unsigned short *val = (unsigned short *) page;
 		char *out = ((char *)val) + (SECTOR_WORDS * 4);
 		page = out;
 		do {
@@ -588,7 +597,7 @@
 	if (!driver)
 		len = sprintf(page, "(none)\n");
         else
-		len = sprintf(page,"%li\n", ((ide_driver_t *)drive->driver)->capacity(drive));
+		len = sprintf(page,"%llu\n", (__u64) ((ide_driver_t *)drive->driver)->capacity(drive));
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
@@ -732,22 +741,57 @@
 	}
 }
 
-void destroy_proc_ide_drives(ide_hwif_t *hwif)
+void recreate_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
 {
-	int	d;
+	struct proc_dir_entry *ent;
+	struct proc_dir_entry *parent = hwif->proc;
+	char name[64];
+//	ide_driver_t *driver = drive->driver;
 
-	for (d = 0; d < MAX_DRIVES; d++) {
-		ide_drive_t *drive = &hwif->drives[d];
-		ide_driver_t *driver = drive->driver;
+	if (drive->present && !drive->proc) {
+		drive->proc = proc_mkdir(drive->name, parent);
+		if (drive->proc)
+			ide_add_proc_entries(drive->proc, generic_drive_entries, drive);
 
-		if (!drive->proc)
-			continue;
+/*
+ * assume that we have these already, however, should test FIXME!
+ * if (driver) {
+ *      ide_add_proc_entries(drive->proc, generic_subdriver_entries, drive);
+ *      ide_add_proc_entries(drive->proc, driver->proc, drive);
+ * }
+ *
+ */
+		sprintf(name,"ide%d/%s", (drive->name[2]-'a')/2, drive->name);
+		ent = proc_symlink(drive->name, proc_ide_root, name);
+		if (!ent)
+			return;
+	}
+}
+
+void destroy_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
+{
+	ide_driver_t *driver = drive->driver;
+
+	if (drive->proc) {
 		if (driver)
 			ide_remove_proc_entries(drive->proc, driver->proc);
 		ide_remove_proc_entries(drive->proc, generic_drive_entries);
 		remove_proc_entry(drive->name, proc_ide_root);
 		remove_proc_entry(drive->name, hwif->proc);
 		drive->proc = NULL;
+	}
+}
+
+void destroy_proc_ide_drives(ide_hwif_t *hwif)
+{
+	int	d;
+
+	for (d = 0; d < MAX_DRIVES; d++) {
+		ide_drive_t *drive = &hwif->drives[d];
+//		ide_driver_t *driver = drive->driver;
+
+		if (drive->proc)
+			destroy_proc_ide_device(hwif, drive);
 	}
 }
 
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/ide-tape.c linux/drivers/ide/ide-tape.c
--- v2.5.2/linux/drivers/ide/ide-tape.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/ide-tape.c	Tue Jan 15 18:57:07 2002
@@ -721,7 +721,7 @@
 	int request_transfer;			/* Bytes to transfer */
 	int actually_transferred;		/* Bytes actually transferred */
 	int buffer_size;			/* Size of our data buffer */
-	struct buffer_head *bh;
+	struct bio *bio;
 	char *b_data;
 	int b_count;
 	byte *buffer;				/* Data buffer */
@@ -805,7 +805,7 @@
  */
 typedef struct idetape_stage_s {
 	struct request rq;			/* The corresponding request */
-	struct buffer_head *bh;			/* The data buffers */
+	struct bio *bio;			/* The data buffers */
 	struct idetape_stage_s *next;		/* Pointer to the next stage */
 	os_aux_t *aux;				/* OnStream aux ptr */
 } idetape_stage_t;
@@ -929,7 +929,7 @@
 	int stage_size;				/* Data buffer size (chosen based on the tape's recommendation */
 	idetape_stage_t *merge_stage;
 	int merge_stage_size;
-	struct buffer_head *bh;
+	struct bio *bio;
 	char *b_data;
 	int b_count;
 	
@@ -1013,7 +1013,7 @@
 	 * Measures number of frames:
 	 *
 	 * 1. written/read to/from the driver pipeline (pipeline_head).
-	 * 2. written/read to/from the tape buffers (buffer_head).
+	 * 2. written/read to/from the tape buffers (bio).
 	 * 3. written/read by the tape to/from the media (tape_head).
 	 */
 	int pipeline_head;
@@ -1493,52 +1493,52 @@
 
 static void idetape_input_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount)
 {
-	struct buffer_head *bh = pc->bh;
+	struct bio *bio = pc->bio;
 	int count;
 
 	while (bcount) {
 #if IDETAPE_DEBUG_BUGS
-		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_input_buffers\n");
+		if (bio == NULL) {
+			printk (KERN_ERR "ide-tape: bio == NULL in idetape_input_buffers\n");
 			idetape_discard_data (drive, bcount);
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (bh->b_size - atomic_read(&bh->b_count), bcount);
-		atapi_input_bytes (drive, bh->b_data + atomic_read(&bh->b_count), count);
+		count = IDE_MIN (bio->bi_size - pc->b_count, bcount);
+		atapi_input_bytes (drive, bio_data(bio) + pc->b_count, count);
 		bcount -= count;
-		atomic_add(count, &bh->b_count);
-		if (atomic_read(&bh->b_count) == bh->b_size) {
-			bh = bh->b_reqnext;
-			if (bh)
-				atomic_set(&bh->b_count, 0);
+		pc->b_count += bio->bi_size;
+		if (pc->b_count == bio->bi_size) {
+			bio = bio->bi_next;
+			if (bio)
+				pc->b_count = 0;
 		}
 	}
-	pc->bh = bh;
+	pc->bio = bio;
 }
 
 static void idetape_output_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount)
 {
-	struct buffer_head *bh = pc->bh;
+	struct bio *bio = pc->bio;
 	int count;
 
 	while (bcount) {
 #if IDETAPE_DEBUG_BUGS
-		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_output_buffers\n");
+		if (bio == NULL) {
+			printk (KERN_ERR "ide-tape: bio == NULL in idetape_output_buffers\n");
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
 		count = IDE_MIN (pc->b_count, bcount);
-		atapi_output_bytes (drive, pc->b_data, count);
+		atapi_output_bytes (drive, bio_data(bio), count);
 		bcount -= count;
 		pc->b_data += count;
 		pc->b_count -= count;
 		if (!pc->b_count) {
-			pc->bh = bh = bh->b_reqnext;
-			if (bh) {
-				pc->b_data = bh->b_data;
-				pc->b_count = atomic_read(&bh->b_count);
+			pc->bio = bio = bio->bi_next;
+			if (bio) {
+				pc->b_data = bio_data(bio);
+				pc->b_count = bio->bi_size;
 			}
 		}
 	}
@@ -1547,25 +1547,25 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA
 static void idetape_update_buffers (idetape_pc_t *pc)
 {
-	struct buffer_head *bh = pc->bh;
+	struct bio *bio = pc->bio;
 	int count, bcount = pc->actually_transferred;
 
 	if (test_bit (PC_WRITING, &pc->flags))
 		return;
 	while (bcount) {
 #if IDETAPE_DEBUG_BUGS
-		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_update_buffers\n");
+		if (bio == NULL) {
+			printk (KERN_ERR "ide-tape: bio == NULL in idetape_update_buffers\n");
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (bh->b_size, bcount);
-		atomic_set(&bh->b_count, count);
-		if (atomic_read(&bh->b_count) == bh->b_size)
-			bh = bh->b_reqnext;
+		count = IDE_MIN (bio->bi_size, bcount);
+		pc->b_count = count;
+		if (pc->b_count == bio->bi_size)
+			bio = bio->bi_next;
 		bcount -= count;
 	}
-	pc->bh = bh;
+	pc->bio = bio;
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
@@ -1625,7 +1625,7 @@
 	pc->request_transfer = 0;
 	pc->buffer = pc->pc_buffer;
 	pc->buffer_size = IDETAPE_PC_BUFFER_SIZE;
-	pc->bh = NULL;
+	pc->bio = NULL;
 	pc->b_data = NULL;
 }
 
@@ -1706,10 +1706,10 @@
 		printk(KERN_INFO "ide-tape: %s: idetape_abort_pipeline called\n", tape->name);
 #endif
 	while (stage) {
-		if (stage->rq.cmd == IDETAPE_WRITE_RQ)
-			stage->rq.cmd = IDETAPE_ABORTED_WRITE_RQ;
-		else if (stage->rq.cmd == IDETAPE_READ_RQ)
-			stage->rq.cmd = IDETAPE_ABORTED_READ_RQ;
+		if (stage->rq.flags == IDETAPE_WRITE_RQ)
+			stage->rq.flags = IDETAPE_ABORTED_WRITE_RQ;
+		else if (stage->rq.flags == IDETAPE_READ_RQ)
+			stage->rq.flags = IDETAPE_ABORTED_READ_RQ;
 		stage = stage->next;
 	}
 }
@@ -1735,7 +1735,7 @@
 #endif /* IDETAPE_DEBUG_BUGS */	
 
 	rq->buffer = NULL;
-	rq->bh = stage->bh;
+	rq->bio = stage->bio;
 	tape->active_data_request = rq;
 	tape->active_stage = stage;
 	tape->next_stage = stage->next;
@@ -1769,21 +1769,21 @@
  */
 static void __idetape_kfree_stage (idetape_stage_t *stage)
 {
-	struct buffer_head *prev_bh, *bh = stage->bh;
+	struct bio *prev_bio, *bio = stage->bio;
 	int size;
 
-	while (bh != NULL) {
-		if (bh->b_data != NULL) {
-			size = (int) bh->b_size;
+	while (bio != NULL) {
+		if (bio_data(bio) != NULL) {
+			size = (int) bio->bi_size;
 			while (size > 0) {
-				free_page ((unsigned long) bh->b_data);
+				free_page ((unsigned long) bio_data(bio));
 				size -= PAGE_SIZE;
-				bh->b_data += PAGE_SIZE;
+				bio->bi_size += PAGE_SIZE;
 			}
 		}
-		prev_bh = bh;
-		bh = bh->b_reqnext;
-		kfree (prev_bh);
+		prev_bio = bio;
+		bio = bio->bi_next;
+		kfree (prev_bio);
 	}
 	kfree (stage);
 }
@@ -1868,13 +1868,13 @@
 		tape->active_stage = NULL;
 		tape->active_data_request = NULL;
 		tape->nr_pending_stages--;
-		if (rq->cmd == IDETAPE_WRITE_RQ) {
+		if (rq->flags == IDETAPE_WRITE_RQ) {
 #if ONSTREAM_DEBUG
 			if (tape->debug_level >= 2) {
 				if (tape->onstream) {
 					stage = tape->first_stage;
 					aux = stage->aux;
-					p = stage->bh->b_data;
+					p = bio_data(stage->bio);
 					if (ntohl(aux->logical_blk_num) < 11300 && ntohl(aux->logical_blk_num) > 11100)
 						printk(KERN_INFO "ide-tape: finished writing logical blk %u (data %x %x %x %x)\n", ntohl(aux->logical_blk_num), *p++, *p++, *p++, *p++);
 				}
@@ -1908,7 +1908,7 @@
 						complete(tape->waiting);
 				}
 			}
-		} else if (rq->cmd == IDETAPE_READ_RQ) {
+		} else if (rq->flags == IDETAPE_READ_RQ) {
 			if (error == IDETAPE_ERROR_EOD) {
 				set_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
 				idetape_abort_pipeline(drive);
@@ -1984,7 +1984,7 @@
 {
 	ide_init_drive_cmd (rq);
 	rq->buffer = (char *) pc;
-	rq->cmd = IDETAPE_PC_RQ1;
+	rq->flags = IDETAPE_PC_RQ1;
 	(void) ide_do_drive_cmd (drive, rq, ide_preempt);
 }
 
@@ -2164,12 +2164,12 @@
 		}
 	}
 	if (test_bit (PC_WRITING, &pc->flags)) {
-		if (pc->bh != NULL)
+		if (pc->bio != NULL)
 			idetape_output_buffers (drive, pc, bcount.all);
 		else
 			atapi_output_bytes (drive,pc->current_position,bcount.all);	/* Write the current buffer */
 	} else {
-		if (pc->bh != NULL)
+		if (pc->bio != NULL)
 			idetape_input_buffers (drive, pc, bcount.all);
 		else
 			atapi_input_bytes (drive,pc->current_position,bcount.all);	/* Read the current buffer */
@@ -2523,21 +2523,22 @@
 	return ide_stopped;
 }
 
-static void idetape_create_read_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct buffer_head *bh)
+static void idetape_create_read_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct bio *bio)
 {
-	struct buffer_head *p = bh;
+	struct bio *p = bio;
+	struct bio_vec *bv = bio_iovec(p);
 	idetape_init_pc (pc);
 	pc->c[0] = IDETAPE_READ_CMD;
 	put_unaligned (htonl (length), (unsigned int *) &pc->c[1]);
 	pc->c[1] = 1;
 	pc->callback = &idetape_rw_callback;
-	pc->bh = bh;
-	atomic_set(&bh->b_count, 0);
+	pc->bio = bio;
+	bv->bv_len = 0;
 	pc->buffer = NULL;
 	if (tape->onstream) {
 		while (p) {
-			atomic_set(&p->b_count, 0);
-			p = p->b_reqnext;
+			bv->bv_len = 0;
+			p = p->bi_next;
 		}
 	}
 	if (!tape->onstream) {
@@ -2553,30 +2554,31 @@
 	}
 }
 
-static void idetape_create_read_buffer_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct buffer_head *bh)
+static void idetape_create_read_buffer_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct bio *bio)
 {
 	int size = 32768;
 
-	struct buffer_head *p = bh;
+	struct bio *p = bio;
 	idetape_init_pc (pc);
 	pc->c[0] = IDETAPE_READ_BUFFER_CMD;
 	pc->c[1] = IDETAPE_RETRIEVE_FAULTY_BLOCK;
 	pc->c[7] = size >> 8;
 	pc->c[8] = size & 0xff;
 	pc->callback = &idetape_pc_callback;
-	pc->bh = bh;
-	atomic_set(&bh->b_count, 0);
+	pc->bio = bio;
+	atomic_set(&bio->bi_cnt, 0);
 	pc->buffer = NULL;
 	while (p) {
-		atomic_set(&p->b_count, 0);
-		p = p->b_reqnext;
+		p->bi_size = 0;
+		p = p->bi_next;
 	}
 	pc->request_transfer = pc->buffer_size = size;
 }
 
-static void idetape_create_write_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct buffer_head *bh)
+static void idetape_create_write_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct bio *bio)
 {
-	struct buffer_head *p = bh;
+	struct bio *p = bio;
+	struct bio_vec *bv= bio_iovec(p);
 	idetape_init_pc (pc);
 	pc->c[0] = IDETAPE_WRITE_CMD;
 	put_unaligned (htonl (length), (unsigned int *) &pc->c[1]);
@@ -2585,13 +2587,13 @@
 	set_bit (PC_WRITING, &pc->flags);
 	if (tape->onstream) {
 		while (p) {
-			atomic_set(&p->b_count, p->b_size);
-			p = p->b_reqnext;
+			bv->bv_len = p->bi_size;
+			p = p->bi_next;
 		}
 	}
-	pc->bh = bh;
-	pc->b_data = bh->b_data;
-	pc->b_count = atomic_read(&bh->b_count);
+	pc->bio = bio;
+	pc->b_data = bio_data(bio);
+	pc->b_count = bio->bi_size;
 	pc->buffer = NULL;
 	if (!tape->onstream) {
 		pc->request_transfer = pc->buffer_size = length * tape->tape_block_size;
@@ -2618,16 +2620,16 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 5)
-		printk (KERN_INFO "ide-tape: rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors);
+/*		printk (KERN_INFO "ide-tape: rq_status: %d, rq_dev: %u, cmd: %ld, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->flags,rq->errors); */
 	if (tape->debug_level >= 2)
-		printk (KERN_INFO "ide-tape: sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
+		printk (KERN_INFO "ide-tape: sector: %ld, nr_sectors: %ld, current_nr_sectors: %d\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
 #endif /* IDETAPE_DEBUG_LOG */
 
-	if (!IDETAPE_RQ_CMD (rq->cmd)) {
+	if (!IDETAPE_RQ_CMD (rq->flags)) {
 		/*
 		 *	We do not support buffer cache originated requests.
 		 */
-		printk (KERN_NOTICE "ide-tape: %s: Unsupported command in request queue (%d)\n", drive->name, rq->cmd);
+		printk (KERN_NOTICE "ide-tape: %s: Unsupported command in request queue (%ld)\n", drive->name, rq->flags);
 		ide_end_request (0, HWGROUP (drive));			/* Let the common code handle it */
 		return ide_stopped;
 	}
@@ -2661,7 +2663,7 @@
 	 */
 	if (tape->onstream)
 		status.b.dsc = 1;
-	if (!drive->dsc_overlap && rq->cmd != IDETAPE_PC_RQ2)
+	if (!drive->dsc_overlap && rq->flags != IDETAPE_PC_RQ2)
 		set_bit (IDETAPE_IGNORE_DSC, &tape->flags);
 
 	/*
@@ -2674,7 +2676,7 @@
 	 */
 	if (tape->tape_still_time > 100 && tape->tape_still_time < 200)
 		tape->measure_insert_time = 1;
-	if (tape->req_buffer_fill && (rq->cmd == IDETAPE_WRITE_RQ || rq->cmd == IDETAPE_READ_RQ)) {
+	if (tape->req_buffer_fill && (rq->flags == IDETAPE_WRITE_RQ || rq->flags == IDETAPE_READ_RQ)) {
 		tape->req_buffer_fill = 0;
 		tape->writes_since_buffer_fill = 0;
 		tape->reads_since_buffer_fill = 0;
@@ -2688,19 +2690,19 @@
 		tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
 	calculate_speeds(drive);
 	if (tape->onstream && tape->max_frames &&
-	    ((rq->cmd == IDETAPE_WRITE_RQ &&
+	    ((rq->flags == IDETAPE_WRITE_RQ &&
               ( tape->cur_frames == tape->max_frames ||
                 ( tape->speed_control && tape->cur_frames > 5 &&
                        (tape->insert_speed > tape->max_insert_speed ||
                         (0 /* tape->cur_frames > 30 && tape->tape_still_time > 200 */) ) ) ) ) ||
-	     (rq->cmd == IDETAPE_READ_RQ &&
+	     (rq->flags == IDETAPE_READ_RQ &&
 	      ( tape->cur_frames == 0 ||
 		( tape->speed_control && (tape->cur_frames < tape->max_frames - 5) &&
 			tape->insert_speed > tape->max_insert_speed ) ) && rq->nr_sectors) ) ) {
 #if IDETAPE_DEBUG_LOG
 		if (tape->debug_level >= 4)
-			printk(KERN_INFO "ide-tape: postponing request, cmd %d, cur %d, max %d\n",
-				rq->cmd, tape->cur_frames, tape->max_frames);
+			printk(KERN_INFO "ide-tape: postponing request, cmd %ld, cur %d, max %d\n",
+				rq->flags, tape->cur_frames, tape->max_frames);
 #endif
 		if (tape->postpone_cnt++ < 500) {
 			status.b.dsc = 0;
@@ -2718,7 +2720,7 @@
 			tape->dsc_timeout = jiffies + IDETAPE_DSC_RW_TIMEOUT;
 		} else if ((signed long) (jiffies - tape->dsc_timeout) > 0) {
 			printk (KERN_ERR "ide-tape: %s: DSC timeout\n", tape->name);
-			if (rq->cmd == IDETAPE_PC_RQ2) {
+			if (rq->flags == IDETAPE_PC_RQ2) {
 				idetape_media_access_finished (drive);
 				return ide_stopped;
 			} else {
@@ -2729,7 +2731,7 @@
 		idetape_postpone_request (drive);
 		return ide_stopped;
 	}
-	switch (rq->cmd) {
+	switch (rq->flags) {
 		case IDETAPE_READ_RQ:
 			tape->buffer_head++;
 #if USE_IOTRACE
@@ -2744,7 +2746,7 @@
 					tape->req_buffer_fill = 1;
 			}
 			pc = idetape_next_pc_storage (drive);
-			idetape_create_read_cmd (tape, pc, rq->current_nr_sectors, rq->bh);
+			idetape_create_read_cmd (tape, pc, rq->current_nr_sectors, rq->bio);
 			break;
 		case IDETAPE_WRITE_RQ:
 			tape->buffer_head++;
@@ -2761,15 +2763,15 @@
 				calculate_speeds(drive);
 			}
 			pc = idetape_next_pc_storage (drive);
-			idetape_create_write_cmd (tape, pc, rq->current_nr_sectors, rq->bh);
+			idetape_create_write_cmd (tape, pc, rq->current_nr_sectors, rq->bio);
 			break;
 		case IDETAPE_READ_BUFFER_RQ:
 			tape->postpone_cnt = 0;
 			pc = idetape_next_pc_storage (drive);
-			idetape_create_read_buffer_cmd (tape, pc, rq->current_nr_sectors, rq->bh);
+			idetape_create_read_buffer_cmd (tape, pc, rq->current_nr_sectors, rq->bio);
 			break;
 		case IDETAPE_ABORTED_WRITE_RQ:
-			rq->cmd = IDETAPE_WRITE_RQ;
+			rq->flags = IDETAPE_WRITE_RQ;
 			idetape_end_request (IDETAPE_ERROR_EOD, HWGROUP(drive));
 			return ide_stopped;
 		case IDETAPE_ABORTED_READ_RQ:
@@ -2777,12 +2779,12 @@
 			if (tape->debug_level >= 2)
 				printk(KERN_INFO "ide-tape: %s: detected aborted read rq\n", tape->name);
 #endif
-			rq->cmd = IDETAPE_READ_RQ;
+			rq->flags = IDETAPE_READ_RQ;
 			idetape_end_request (IDETAPE_ERROR_EOD, HWGROUP(drive));
 			return ide_stopped;
 		case IDETAPE_PC_RQ1:
 			pc = (idetape_pc_t *) rq->buffer;
-			rq->cmd = IDETAPE_PC_RQ2;
+			rq->flags = IDETAPE_PC_RQ2;
 			break;
 		case IDETAPE_PC_RQ2:
 			idetape_media_access_finished (drive);
@@ -2822,61 +2824,65 @@
 static idetape_stage_t *__idetape_kmalloc_stage (idetape_tape_t *tape, int full, int clear)
 {
 	idetape_stage_t *stage;
-	struct buffer_head *prev_bh, *bh;
+	struct bio *prev_bio, *bio;
 	int pages = tape->pages_per_stage;
-	char *b_data;
+	char *b_data = NULL;
+	struct bio_vec *bv; 
 
 	if ((stage = (idetape_stage_t *) kmalloc (sizeof (idetape_stage_t),GFP_KERNEL)) == NULL)
 		return NULL;
 	stage->next = NULL;
 
-	bh = stage->bh = (struct buffer_head *) kmalloc (sizeof (struct buffer_head), GFP_KERNEL);
-	if (bh == NULL)
+	bio = stage->bio = bio_alloc(GFP_KERNEL,1);
+	bv = bio_iovec(bio);	
+	bv->bv_len = 0;
+	if (bio == NULL)
 		goto abort;
-	bh->b_reqnext = NULL;
-	if ((bh->b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL)
+	bio->bi_next = NULL;
+	if ((bio->bi_io_vec[0].bv_page = alloc_page(GFP_KERNEL)) == NULL)
 		goto abort;
 	if (clear)
-		memset(bh->b_data, 0, PAGE_SIZE);
-	bh->b_size = PAGE_SIZE;
-	atomic_set(&bh->b_count, full ? bh->b_size : 0);
-	set_bit (BH_Lock, &bh->b_state);
+		memset(bio_data(bio), 0, PAGE_SIZE);
+	bio->bi_size = PAGE_SIZE;
+	if(bv->bv_len == full) bv->bv_len = bio->bi_size;
+	set_bit (BH_Lock, &bio->bi_flags);
 
 	while (--pages) {
-		if ((b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL)
+		if ((bio->bi_io_vec[pages].bv_page = alloc_page(GFP_KERNEL)) == NULL)
 			goto abort;
 		if (clear)
-			memset(b_data, 0, PAGE_SIZE);
-		if (bh->b_data == b_data + PAGE_SIZE) {
-			bh->b_size += PAGE_SIZE;
-			bh->b_data -= PAGE_SIZE;
+			memset(bio_data(bio), 0, PAGE_SIZE);
+		if (bio->bi_size == bv->bv_len + PAGE_SIZE) {
+			bio->bi_size += PAGE_SIZE;
+			bv->bv_len += PAGE_SIZE;
+			bv->bv_offset -= PAGE_SIZE;
 			if (full)
-				atomic_add(PAGE_SIZE, &bh->b_count);
+				bio->bi_size += PAGE_SIZE;
 			continue;
 		}
-		if (b_data == bh->b_data + bh->b_size) {
-			bh->b_size += PAGE_SIZE;
+		if (b_data == bio_data(bio) + bio->bi_size) {
+			bio->bi_size += PAGE_SIZE;
 			if (full)
-				atomic_add(PAGE_SIZE, &bh->b_count);
+				bio->bi_size += PAGE_SIZE;
 			continue;
 		}
-		prev_bh = bh;
-		if ((bh = (struct buffer_head *) kmalloc (sizeof (struct buffer_head), GFP_KERNEL)) == NULL) {
-			free_page ((unsigned long) b_data);
+		prev_bio = bio;
+		if ((bio = bio_alloc(GFP_KERNEL,1)) == NULL) {
+			free_page ((unsigned long) bio_data(bio));
 			goto abort;
 		}
-		bh->b_reqnext = NULL;
-		bh->b_data = b_data;
-		bh->b_size = PAGE_SIZE;
-		atomic_set(&bh->b_count, full ? bh->b_size : 0);
-		set_bit (BH_Lock, &bh->b_state);
-		prev_bh->b_reqnext = bh;
+		bio->bi_next = NULL;
+		//bio->bi_io_vec[0].bv_offset = b_data;
+		bio->bi_size = PAGE_SIZE;
+		atomic_set(&bio->bi_cnt, full ? bio->bi_size : 0);
+		set_bit (BH_Lock, &bio->bi_flags);
+		prev_bio->bi_next = bio;
 	}
-	bh->b_size -= tape->excess_bh_size;
+	bio->bi_size -= tape->excess_bh_size;
 	if (full)
-		atomic_sub(tape->excess_bh_size, &bh->b_count);
+		atomic_sub(tape->excess_bh_size, &bio->bi_cnt);
 	if (tape->onstream)
-		stage->aux = (os_aux_t *) (bh->b_data + bh->b_size - OS_AUX_SIZE);
+		stage->aux = (os_aux_t *) (bio_data(bio) + bio->bi_size - OS_AUX_SIZE);
 	return stage;
 abort:
 	__idetape_kfree_stage (stage);
@@ -2903,39 +2909,39 @@
 
 static void idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char *buf, int n)
 {
-	struct buffer_head *bh = tape->bh;
+	struct bio *bio = tape->bio;
 	int count;
 
 	while (n) {
 #if IDETAPE_DEBUG_BUGS
-		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_copy_stage_from_user\n");
+		if (bio == NULL) {
+			printk (KERN_ERR "ide-tape: bio == NULL in idetape_copy_stage_from_user\n");
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (bh->b_size - atomic_read(&bh->b_count), n);
-		copy_from_user (bh->b_data + atomic_read(&bh->b_count), buf, count);
+		count = IDE_MIN (bio->bi_size - tape->b_count, n);
+		copy_from_user (bio_data(bio) + tape->b_count, buf, count);
 		n -= count;
-		atomic_add(count, &bh->b_count);
+		bio->bi_size += count;
 		buf += count;
-		if (atomic_read(&bh->b_count) == bh->b_size) {
-			bh = bh->b_reqnext;
-			if (bh)
-				atomic_set(&bh->b_count, 0);
+		if (tape->b_count == bio->bi_size) {
+			bio = bio->bi_next;
+			if (bio)
+				tape->b_count = 0;
 		}
 	}
-	tape->bh = bh;
+	tape->bio = bio;
 }
 
 static void idetape_copy_stage_to_user (idetape_tape_t *tape, char *buf, idetape_stage_t *stage, int n)
 {
-	struct buffer_head *bh = tape->bh;
+	struct bio *bio = tape->bio;
 	int count;
 
 	while (n) {
 #if IDETAPE_DEBUG_BUGS
-		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_copy_stage_to_user\n");
+		if (bio == NULL) {
+			printk (KERN_ERR "ide-tape: bio == NULL in idetape_copy_stage_to_user\n");
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
@@ -2946,10 +2952,10 @@
 		tape->b_count -= count;
 		buf += count;
 		if (!tape->b_count) {
-			tape->bh = bh = bh->b_reqnext;
-			if (bh) {
-				tape->b_data = bh->b_data;
-				tape->b_count = atomic_read(&bh->b_count);
+			tape->bio = bio = bio->bi_next;
+			if (bio) {
+				tape->b_data = bio_data(bio);
+				tape->b_count = bio->bi_size;
 			}
 		}
 	}
@@ -2957,25 +2963,25 @@
 
 static void idetape_init_merge_stage (idetape_tape_t *tape)
 {
-	struct buffer_head *bh = tape->merge_stage->bh;
+	struct bio *bio = tape->merge_stage->bio;
 	
-	tape->bh = bh;
+	tape->bio = bio;
 	if (tape->chrdev_direction == idetape_direction_write)
-		atomic_set(&bh->b_count, 0);
+		atomic_set(&bio->bi_cnt, 0);
 	else {
-		tape->b_data = bh->b_data;
-		tape->b_count = atomic_read(&bh->b_count);
+		tape->b_data = bio_data(bio);
+		tape->b_count = atomic_read(&bio->bi_cnt);
 	}
 }
 
 static void idetape_switch_buffers (idetape_tape_t *tape, idetape_stage_t *stage)
 {
-	struct buffer_head *tmp;
+	struct bio *tmp;
 	os_aux_t *tmp_aux;
 
-	tmp = stage->bh; tmp_aux = stage->aux;
-	stage->bh = tape->merge_stage->bh; stage->aux = tape->merge_stage->aux;
-	tape->merge_stage->bh = tmp; tape->merge_stage->aux = tmp_aux;
+	tmp = stage->bio; tmp_aux = stage->aux;
+	stage->bio = tape->merge_stage->bio; stage->aux = tape->merge_stage->aux;
+	tape->merge_stage->bio = tmp; tape->merge_stage->aux = tmp_aux;
 	idetape_init_merge_stage (tape);
 }
 
@@ -3077,7 +3083,7 @@
 	idetape_tape_t *tape = drive->driver_data;
 
 #if IDETAPE_DEBUG_BUGS
-	if (rq == NULL || !IDETAPE_RQ_CMD (rq->cmd)) {
+	if (rq == NULL || !IDETAPE_RQ_CMD (rq->flags)) {
 		printk (KERN_ERR "ide-tape: bug: Trying to sleep on non-valid request\n");
 		return;
 	}
@@ -3185,7 +3191,7 @@
 
 	ide_init_drive_cmd (&rq);
 	rq.buffer = (char *) pc;
-	rq.cmd = IDETAPE_PC_RQ1;
+	rq.flags = IDETAPE_PC_RQ1;
 	return ide_do_drive_cmd (drive, &rq, ide_wait);
 }
 
@@ -3430,7 +3436,7 @@
  *	idetape_queue_rw_tail generates a read/write request for the block
  *	device interface and wait for it to be serviced.
  */
-static int idetape_queue_rw_tail (ide_drive_t *drive, int cmd, int blocks, struct buffer_head *bh)
+static int idetape_queue_rw_tail (ide_drive_t *drive, int cmd, int blocks, struct bio *bio)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	struct request rq;
@@ -3447,8 +3453,8 @@
 #endif /* IDETAPE_DEBUG_BUGS */	
 
 	ide_init_drive_cmd (&rq);
-	rq.bh = bh;
-	rq.cmd = cmd;
+	rq.bio = bio;
+	rq.flags = cmd;
 	rq.sector = tape->first_frame_position;
 	rq.nr_sectors = rq.current_nr_sectors = blocks;
 	if (tape->onstream)
@@ -3489,15 +3495,15 @@
 		if (!first)
 			first = stage;
 		aux = stage->aux;
-		p = stage->bh->b_data;
-		idetape_queue_rw_tail(drive, IDETAPE_READ_BUFFER_RQ, tape->capabilities.ctl, stage->bh);
+		p = bio_data(stage->bio);
+		idetape_queue_rw_tail(drive, IDETAPE_READ_BUFFER_RQ, tape->capabilities.ctl, stage->bio);
 #if ONSTREAM_DEBUG
 		if (tape->debug_level >= 2)
 			printk(KERN_INFO "ide-tape: %s: read back logical block %d, data %x %x %x %x\n", tape->name, logical_blk_num, *p++, *p++, *p++, *p++);
 #endif
 		rq = &stage->rq;
 		ide_init_drive_cmd (rq);
-		rq->cmd = IDETAPE_WRITE_RQ;
+		rq->flags = IDETAPE_WRITE_RQ;
 		rq->sector = tape->first_frame_position;
 		rq->nr_sectors = rq->current_nr_sectors = tape->capabilities.ctl;
 		idetape_init_stage(drive, stage, OS_FRAME_TYPE_DATA, logical_blk_num++);
@@ -3646,18 +3652,18 @@
 	os_aux_t *aux = stage->aux;
 	os_partition_t *par = &aux->partition;
 	struct request *rq = &stage->rq;
-	struct buffer_head *bh;
+	struct bio *bio;
 
 	if (!tape->onstream)
 		return 1;
 	if (tape->raw) {
 		if (rq->errors) {
-			bh = stage->bh;
-			while (bh) {
-				memset(bh->b_data, 0, bh->b_size);
-				bh = bh->b_reqnext;
+			bio = stage->bio;
+			while (bio) {
+				memset(bio_data(bio), 0, bio->bi_size);
+				bio = bio->bi_next;
 			}
-			strcpy(stage->bh->b_data, "READ ERROR ON FRAME");
+			strcpy(bio_data(stage->bio), "READ ERROR ON FRAME");
 		}
 		return 1;
 	}
@@ -3767,12 +3773,12 @@
 			 *	Linux is short on memory. Fallback to
 			 *	non-pipelined operation mode for this request.
 			 */
-			return idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bh);
+			return idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bio);
 		}
 	}
 	rq = &new_stage->rq;
 	ide_init_drive_cmd (rq);
-	rq->cmd = IDETAPE_WRITE_RQ;
+	rq->flags = IDETAPE_WRITE_RQ;
 	rq->sector = tape->first_frame_position;	/* Doesn't actually matter - We always assume sequential access */
 	rq->nr_sectors = rq->current_nr_sectors = blocks;
 
@@ -3843,7 +3849,7 @@
 {
 	idetape_tape_t *tape = drive->driver_data;
 	int blocks, i, min;
-	struct buffer_head *bh;
+	struct bio *bio;
 	
 #if IDETAPE_DEBUG_BUGS
 	if (tape->chrdev_direction != idetape_direction_write) {
@@ -3860,22 +3866,22 @@
 		if (tape->merge_stage_size % tape->tape_block_size) {
 			blocks++;
 			i = tape->tape_block_size - tape->merge_stage_size % tape->tape_block_size;
-			bh = tape->bh->b_reqnext;
-			while (bh) {
-				atomic_set(&bh->b_count, 0);
-				bh = bh->b_reqnext;
+			bio = tape->bio->bi_next;
+			while (bio) {
+				atomic_set(&bio->bi_cnt, 0);
+				bio = bio->bi_next;
 			}
-			bh = tape->bh;
+			bio = tape->bio;
 			while (i) {
-				if (bh == NULL) {
-					printk(KERN_INFO "ide-tape: bug, bh NULL\n");
+				if (bio == NULL) {
+					printk(KERN_INFO "ide-tape: bug, bio NULL\n");
 					break;
 				}
-				min = IDE_MIN(i, bh->b_size - atomic_read(&bh->b_count));
-				memset(bh->b_data + atomic_read(&bh->b_count), 0, min);
-				atomic_add(min, &bh->b_count);
+				min = IDE_MIN(i, bio->bi_size - atomic_read(&bio->bi_cnt));
+				memset(bio_data(bio) + bio->bi_size, 0, min);
+				atomic_add(min, &bio->bi_cnt);
 				i -= min;
-				bh = bh->b_reqnext;
+				bio = bio->bi_next;
 			}
 		}
 		(void) idetape_add_chrdev_write_request (drive, blocks);
@@ -3949,7 +3955,7 @@
 		 *	is switched from completion mode to buffer available
 		 *	mode.
 		 */
-		bytes_read = idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 0, tape->merge_stage->bh);
+		bytes_read = idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 0, tape->merge_stage->bio);
 		if (bytes_read < 0) {
 			kfree (tape->merge_stage);
 			tape->merge_stage = NULL;
@@ -3960,7 +3966,7 @@
 	if (tape->restart_speed_control_req)
 		idetape_restart_speed_control(drive);
 	ide_init_drive_cmd (&rq);
-	rq.cmd = IDETAPE_READ_RQ;
+	rq.flags = IDETAPE_READ_RQ;
 	rq.sector = tape->first_frame_position;
 	rq.nr_sectors = rq.current_nr_sectors = blocks;
 	if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) && tape->nr_stages <= max_stages) {
@@ -4083,7 +4089,7 @@
 		}
 		if (test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags))
 		 	return 0;
-		return idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, blocks, tape->merge_stage->bh);
+		return idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, blocks, tape->merge_stage->bio);
 	}
 	rq_ptr = &tape->first_stage->rq;
 	bytes_read = tape->tape_block_size * (rq_ptr->nr_sectors - rq_ptr->current_nr_sectors);
@@ -4137,21 +4143,21 @@
 static void idetape_pad_zeros (ide_drive_t *drive, int bcount)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	struct buffer_head *bh;
+	struct bio *bio;
 	int count, blocks;
 	
 	while (bcount) {
-		bh = tape->merge_stage->bh;
+		bio = tape->merge_stage->bio;
 		count = IDE_MIN (tape->stage_size, bcount);
 		bcount -= count;
 		blocks = count / tape->tape_block_size;
 		while (count) {
-			atomic_set(&bh->b_count, IDE_MIN (count, bh->b_size));
-			memset (bh->b_data, 0, atomic_read(&bh->b_count));
-			count -= atomic_read(&bh->b_count);
-			bh = bh->b_reqnext;
+			atomic_set(&bio->bi_cnt, IDE_MIN (count, bio->bi_size));
+			memset (bio_data(bio), 0, bio->bi_size);
+			count -= atomic_read(&bio->bi_cnt);
+			bio = bio->bi_next;
 		}
-		idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bh);
+		idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bio);
 	}
 }
 
@@ -4276,7 +4282,7 @@
  */
 static ide_drive_t *get_drive_ptr (kdev_t i_rdev)
 {
-	unsigned int i = MINOR(i_rdev) & ~0xc0;
+	unsigned int i = minor(i_rdev) & ~0xc0;
 
 	if (i >= MAX_HWIFS * MAX_DRIVES)
 		return NULL;
@@ -4654,7 +4660,7 @@
 		printk(KERN_INFO "ide-tape: current position (2) tape block %d\n", tape->last_frame_position);
 #endif
 	idetape_position_tape(drive, last_mark_addr, 0, 0);
-	if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bh)) {
+	if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bio)) {
 		printk(KERN_INFO "ide-tape: %s: couldn't read last marker\n", tape->name);
 		__idetape_kfree_stage (stage);
 		idetape_position_tape(drive, position, 0, 0);
@@ -4673,7 +4679,7 @@
 #endif
 	aux->next_mark_addr = htonl(next_mark_addr);
 	idetape_position_tape(drive, last_mark_addr, 0, 0);
-	if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
+	if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bio)) {
 		printk(KERN_INFO "ide-tape: %s: couldn't write back marker frame at %d\n", tape->name, last_mark_addr);
 		__idetape_kfree_stage (stage);
 		idetape_position_tape(drive, position, 0, 0);
@@ -4705,9 +4711,9 @@
 	if (rc != 0) 
 		return;	/* don't write fillers if we cannot position the tape. */
 
-	strcpy(stage->bh->b_data, "Filler");
+	strcpy(bio_data(stage->bio), "Filler");
 	while (cnt--) {
-		if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
+		if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bio)) {
 			printk(KERN_INFO "ide-tape: %s: write_filler: couldn't write header frame\n", tape->name);
 			__idetape_kfree_stage (stage);
 			return;
@@ -4739,9 +4745,9 @@
 	header.partition.last_frame_addr = htonl(tape->capacity);
 	header.partition.wrt_pass_cntr = htons(tape->wrt_pass_cntr);
 	header.partition.eod_frame_addr = htonl(tape->eod_frame_addr);
-	memcpy(stage->bh->b_data, &header, sizeof(header));
+	memcpy(bio_data(stage->bio), &header, sizeof(header));
 	while (cnt--) {
-		if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
+		if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bio)) {
 			printk(KERN_INFO "ide-tape: %s: couldn't write header frame\n", tape->name);
 			__idetape_kfree_stage (stage);
 			return;
@@ -4860,7 +4866,7 @@
 		 *	is switched from completion mode to buffer available
 		 *	mode.
 		 */
-		retval = idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 0, tape->merge_stage->bh);
+		retval = idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 0, tape->merge_stage->bio);
 		if (retval < 0) {
 			kfree (tape->merge_stage);
 			tape->merge_stage = NULL;
@@ -5326,12 +5332,12 @@
 		printk(KERN_INFO "ide-tape: %s: reading header\n", tape->name);
 #endif
 	idetape_position_tape(drive, block, 0, 0);
-	if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bh)) {
+	if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bio)) {
 		printk(KERN_INFO "ide-tape: %s: couldn't read header frame\n", tape->name);
 		__idetape_kfree_stage (stage);
 		return 0;
 	}
-	header = (os_header_t *) stage->bh->b_data;
+	header = (os_header_t *) bio_data(stage->bio);
 	aux = stage->aux;
 	if (strncmp(header->ident_str, "ADR_SEQ", 7) != 0) {
 		printk(KERN_INFO "ide-tape: %s: invalid header identification string\n", tape->name);
@@ -5403,7 +5409,7 @@
 	ide_drive_t *drive;
 	idetape_tape_t *tape;
 	idetape_pc_t pc;
-	unsigned int minor=MINOR (inode->i_rdev);
+	unsigned int minor=minor(inode->i_rdev);
 			
 #if IDETAPE_DEBUG_LOG
 	printk (KERN_INFO "ide-tape: Reached idetape_chrdev_open\n");
@@ -5460,7 +5466,7 @@
 {
 	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
 	idetape_tape_t *tape = drive->driver_data;
-	unsigned int minor=MINOR (inode->i_rdev);
+	unsigned int minor=minor(inode->i_rdev);
 
 	idetape_empty_write_pipeline (drive);
 	tape->merge_stage = __idetape_kmalloc_stage (tape, 1, 0);
@@ -5486,7 +5492,7 @@
 	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
 	idetape_tape_t *tape;
 	idetape_pc_t pc;
-	unsigned int minor=MINOR (inode->i_rdev);
+	unsigned int minor=minor(inode->i_rdev);
 
 	tape = drive->driver_data;
 #if IDETAPE_DEBUG_LOG
@@ -6130,10 +6136,7 @@
 
 #endif
 
-static int idetape_reinit (ide_drive_t *drive)
-{
-	return 0;
-}
+int idetape_reinit(ide_drive_t *drive);
 
 /*
  *	IDE subdriver functions, registered with ide.c
@@ -6146,6 +6149,8 @@
 	supports_dma:		1,
 	supports_dsc_overlap: 	1,
 	cleanup:		idetape_cleanup,
+	standby:		NULL,
+	flushcache:		NULL,
 	do_request:		idetape_do_request,
 	end_request:		idetape_end_request,
 	ioctl:			idetape_blkdev_ioctl,
@@ -6179,6 +6184,92 @@
 	release:	idetape_chrdev_release,
 };
 
+int idetape_reinit (ide_drive_t *drive)
+{
+#if 0
+	idetape_tape_t *tape;
+	int minor, failed = 0, supported = 0;
+/* DRIVER(drive)->busy++; */
+	MOD_INC_USE_COUNT;
+#if ONSTREAM_DEBUG
+        printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_init\n");
+#endif
+	if (!idetape_chrdev_present)
+		for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++ )
+			idetape_chrdevs[minor].drive = NULL;
+
+	if ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) == NULL) {
+		ide_register_module (&idetape_module);
+		MOD_DEC_USE_COUNT;
+#if ONSTREAM_DEBUG
+		printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
+#endif
+		return 0;
+	}
+	if (!idetape_chrdev_present &&
+	    devfs_register_chrdev (IDETAPE_MAJOR, "ht", &idetape_fops)) {
+		printk (KERN_ERR "ide-tape: Failed to register character device interface\n");
+		MOD_DEC_USE_COUNT;
+#if ONSTREAM_DEBUG
+		printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
+#endif
+		return -EBUSY;
+	}
+	do {
+		if (!idetape_identify_device (drive, drive->id)) {
+			printk (KERN_ERR "ide-tape: %s: not supported by this version of ide-tape\n", drive->name);
+			continue;
+		}
+		if (drive->scsi) {
+			if (strstr(drive->id->model, "OnStream DI-30")) {
+				printk("ide-tape: ide-scsi emulation is not supported for %s.\n", drive->id->model);
+			} else {
+				printk("ide-tape: passing drive %s to ide-scsi emulation.\n", drive->name);
+				continue;
+			}
+		}
+		tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL);
+		if (tape == NULL) {
+			printk (KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name);
+			continue;
+		}
+		if (ide_register_subdriver (drive, &idetape_driver, IDE_SUBDRIVER_VERSION)) {
+			printk (KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name);
+			kfree (tape);
+			continue;
+		}
+		for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++);
+		idetape_setup (drive, tape, minor);
+		idetape_chrdevs[minor].drive = drive;
+		tape->de_r =
+		    devfs_register (drive->de, "mt", DEVFS_FL_DEFAULT,
+				    HWIF(drive)->major, minor,
+				    S_IFCHR | S_IRUGO | S_IWUGO,
+				    &idetape_fops, NULL);
+		tape->de_n =
+		    devfs_register (drive->de, "mtn", DEVFS_FL_DEFAULT,
+				    HWIF(drive)->major, minor + 128,
+				    S_IFCHR | S_IRUGO | S_IWUGO,
+				    &idetape_fops, NULL);
+		devfs_register_tape (tape->de_r);
+		supported++; failed--;
+	} while ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) != NULL);
+	if (!idetape_chrdev_present && !supported) {
+		devfs_unregister_chrdev (IDETAPE_MAJOR, "ht");
+	} else
+		idetape_chrdev_present = 1;
+	ide_register_module (&idetape_module);
+	MOD_DEC_USE_COUNT;
+#if ONSTREAM_DEBUG
+	printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
+#endif
+
+	return 0;
+#else
+	return 1;
+#endif
+}
+
 MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver");
 MODULE_LICENSE("GPL");
 
@@ -6203,7 +6294,7 @@
 	ide_drive_t *drive;
 	idetape_tape_t *tape;
 	int minor, failed = 0, supported = 0;
-
+/* DRIVER(drive)->busy++; */
 	MOD_INC_USE_COUNT;
 #if ONSTREAM_DEBUG
         printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_init\n");
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/ide-taskfile.c linux/drivers/ide/ide-taskfile.c
--- v2.5.2/linux/drivers/ide/ide-taskfile.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/ide/ide-taskfile.c	Thu Jan 17 13:58:35 2002
@@ -0,0 +1,1863 @@
+/*
+ * linux/drivers/ide/ide-taskfile.c	Version 0.20	Oct 11, 2000
+ *
+ *  Copyright (C) 2000		Michael Cornwell <cornwell@acm.org>
+ *  Copyright (C) 2000		Andre Hedrick <andre@linux-ide.org>
+ *
+ *  May be copied or modified under the terms of the GNU General Public License
+ *
+ * IDE_DEBUG(__LINE__);
+ */
+
+#include <linux/config.h>
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/genhd.h>
+#include <linux/blkpg.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+
+#define DEBUG_TASKFILE	0	/* unset when fixed */
+
+#if DEBUG_TASKFILE
+#define DTF(x...) printk(##x)
+#else
+#define DTF(x...)
+#endif
+
+inline u32 task_read_24 (ide_drive_t *drive)
+{
+	return	(IN_BYTE(IDE_HCYL_REG)<<16) |
+		(IN_BYTE(IDE_LCYL_REG)<<8) |
+		 IN_BYTE(IDE_SECTOR_REG);
+}
+
+static void ata_bswap_data (void *buffer, int wcount)
+{
+	u16 *p = buffer;
+
+	while (wcount--) {
+		*p = *p << 8 | *p >> 8; p++;
+		*p = *p << 8 | *p >> 8; p++;
+	}
+}
+
+#if SUPPORT_VLB_SYNC
+/*
+ * Some localbus EIDE interfaces require a special access sequence
+ * when using 32-bit I/O instructions to transfer data.  We call this
+ * the "vlb_sync" sequence, which consists of three successive reads
+ * of the sector count register location, with interrupts disabled
+ * to ensure that the reads all happen together.
+ */
+static inline void task_vlb_sync (ide_ioreg_t port) {
+	(void) IN_BYTE (port);
+	(void) IN_BYTE (port);
+	(void) IN_BYTE (port);
+}
+#endif /* SUPPORT_VLB_SYNC */
+
+/*
+ * This is used for most PIO data transfers *from* the IDE interface
+ */
+void ata_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+{
+	byte io_32bit;
+
+	/*
+	 * first check if this controller has defined a special function
+	 * for handling polled ide transfers
+	 */
+
+	if (HWIF(drive)->ideproc) {
+		HWIF(drive)->ideproc(ideproc_ide_input_data, drive, buffer, wcount);
+		return;
+	}
+
+	io_32bit = drive->io_32bit;
+
+	if (io_32bit) {
+#if SUPPORT_VLB_SYNC
+		if (io_32bit & 2) {
+			unsigned long flags;
+			__save_flags(flags);	/* local CPU only */
+			__cli();		/* local CPU only */
+			task_vlb_sync(IDE_NSECTOR_REG);
+			insl(IDE_DATA_REG, buffer, wcount);
+			__restore_flags(flags);	/* local CPU only */
+		} else
+#endif /* SUPPORT_VLB_SYNC */
+			insl(IDE_DATA_REG, buffer, wcount);
+	} else {
+#if SUPPORT_SLOW_DATA_PORTS
+		if (drive->slow) {
+			unsigned short *ptr = (unsigned short *) buffer;
+			while (wcount--) {
+				*ptr++ = inw_p(IDE_DATA_REG);
+				*ptr++ = inw_p(IDE_DATA_REG);
+			}
+		} else
+#endif /* SUPPORT_SLOW_DATA_PORTS */
+			insw(IDE_DATA_REG, buffer, wcount<<1);
+	}
+}
+
+/*
+ * This is used for most PIO data transfers *to* the IDE interface
+ */
+void ata_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+{
+	byte io_32bit;
+
+	if (HWIF(drive)->ideproc) {
+		HWIF(drive)->ideproc(ideproc_ide_output_data, drive, buffer, wcount);
+		return;
+	}
+
+	io_32bit = drive->io_32bit;
+
+	if (io_32bit) {
+#if SUPPORT_VLB_SYNC
+		if (io_32bit & 2) {
+			unsigned long flags;
+			__save_flags(flags);	/* local CPU only */
+			__cli();		/* local CPU only */
+			task_vlb_sync(IDE_NSECTOR_REG);
+			outsl(IDE_DATA_REG, buffer, wcount);
+			__restore_flags(flags);	/* local CPU only */
+		} else
+#endif /* SUPPORT_VLB_SYNC */
+			outsl(IDE_DATA_REG, buffer, wcount);
+	} else {
+#if SUPPORT_SLOW_DATA_PORTS
+		if (drive->slow) {
+			unsigned short *ptr = (unsigned short *) buffer;
+			while (wcount--) {
+				outw_p(*ptr++, IDE_DATA_REG);
+				outw_p(*ptr++, IDE_DATA_REG);
+			}
+		} else
+#endif /* SUPPORT_SLOW_DATA_PORTS */
+			outsw(IDE_DATA_REG, buffer, wcount<<1);
+	}
+}
+
+/*
+ * The following routines are mainly used by the ATAPI drivers.
+ *
+ * These routines will round up any request for an odd number of bytes,
+ * so if an odd bytecount is specified, be sure that there's at least one
+ * extra byte allocated for the buffer.
+ */
+void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
+{
+	if (HWIF(drive)->ideproc) {
+		HWIF(drive)->ideproc(ideproc_atapi_input_bytes, drive, buffer, bytecount);
+		return;
+	}
+
+	++bytecount;
+#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
+	if (MACH_IS_ATARI || MACH_IS_Q40) {
+		/* Atari has a byte-swapped IDE interface */
+		insw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
+		return;
+	}
+#endif /* CONFIG_ATARI */
+	ata_input_data (drive, buffer, bytecount / 4);
+	if ((bytecount & 0x03) >= 2)
+		insw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);
+}
+
+void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
+{
+	if (HWIF(drive)->ideproc) {
+		HWIF(drive)->ideproc(ideproc_atapi_output_bytes, drive, buffer, bytecount);
+		return;
+	}
+
+	++bytecount;
+#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
+	if (MACH_IS_ATARI || MACH_IS_Q40) {
+		/* Atari has a byte-swapped IDE interface */
+		outsw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
+		return;
+	}
+#endif /* CONFIG_ATARI */
+	ata_output_data (drive, buffer, bytecount / 4);
+	if ((bytecount & 0x03) >= 2)
+		outsw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);
+}
+
+void taskfile_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+{
+	ata_input_data(drive, buffer, wcount);
+	if (drive->bswap)
+		ata_bswap_data(buffer, wcount);
+}
+
+void taskfile_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+{
+	if (drive->bswap) {
+		ata_bswap_data(buffer, wcount);
+		ata_output_data(drive, buffer, wcount);
+		ata_bswap_data(buffer, wcount);
+	} else {
+		ata_output_data(drive, buffer, wcount);
+	}
+}
+
+/*
+ * Needed for PCI irq sharing
+ */
+int drive_is_ready (ide_drive_t *drive)
+{
+	byte stat = 0;
+	if (drive->waiting_for_dma)
+		return HWIF(drive)->dmaproc(ide_dma_test_irq, drive);
+#if 0
+	/* need to guarantee 400ns since last command was issued */
+	udelay(1);
+#endif
+
+#ifdef CONFIG_IDEPCI_SHARE_IRQ
+	/*
+	 * We do a passive status test under shared PCI interrupts on
+	 * cards that truly share the ATA side interrupt, but may also share
+	 * an interrupt with another pci card/device.  We make no assumptions
+	 * about possible isa-pnp and pci-pnp issues yet.
+	 */
+	if (IDE_CONTROL_REG)
+		stat = GET_ALTSTAT();
+	else
+#endif /* CONFIG_IDEPCI_SHARE_IRQ */
+	stat = GET_STAT();	/* Note: this may clear a pending IRQ!! */
+
+	if (stat & BUSY_STAT)
+		return 0;	/* drive busy:  definitely not interrupting */
+	return 1;		/* drive ready: *might* be interrupting */
+}
+
+ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
+{
+	task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
+	hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister;
+	struct hd_driveid *id = drive->id;
+	byte HIHI = (drive->addressing) ? 0xE0 : 0xEF;
+
+	/* (ks/hs): Moved to start, do not use for multiple out commands */
+	if (task->handler != task_mulout_intr) {
+		if (IDE_CONTROL_REG)
+			OUT_BYTE(drive->ctl, IDE_CONTROL_REG);	/* clear nIEN */
+		SELECT_MASK(HWIF(drive), drive, 0);
+	}
+
+	if ((id->command_set_2 & 0x0400) &&
+	    (id->cfs_enable_2 & 0x0400) &&
+	    (drive->addressing == 1)) {
+		OUT_BYTE(hobfile->feature, IDE_FEATURE_REG);
+		OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG);
+		OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG);
+		OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG);
+		OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG);
+	}
+
+	OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
+	OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
+	/* refers to number of sectors to transfer */
+	OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
+	/* refers to sector offset or start sector */
+	OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
+	OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
+
+	OUT_BYTE((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
+	if (task->handler != NULL) {
+		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
+		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
+		/*
+		 * warning check for race between handler and prehandler for
+		 * writing first block of data.  however since we are well
+		 * inside the boundaries of the seek, we should be okay.
+		 */
+		if (task->prehandler != NULL) {
+			return task->prehandler(drive, task->rq);
+		}
+	} else {
+		/* for dma commands we down set the handler */
+		if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
+	}
+
+	return ide_started;
+}
+
+void do_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, ide_handler_t *handler)
+{
+	struct hd_driveid *id = drive->id;
+	byte HIHI = (drive->addressing) ? 0xE0 : 0xEF;
+
+	/* (ks/hs): Moved to start, do not use for multiple out commands */
+	if (*handler != task_mulout_intr) {
+		if (IDE_CONTROL_REG)
+			OUT_BYTE(drive->ctl, IDE_CONTROL_REG);  /* clear nIEN */
+		SELECT_MASK(HWIF(drive), drive, 0);
+	}
+
+	if ((id->command_set_2 & 0x0400) &&
+	    (id->cfs_enable_2 & 0x0400) &&
+	    (drive->addressing == 1)) {
+		OUT_BYTE(hobfile->feature, IDE_FEATURE_REG);
+		OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG);
+		OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG);
+		OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG);
+		OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG);
+	}
+
+	OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
+	OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
+	/* refers to number of sectors to transfer */
+	OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
+	/* refers to sector offset or start sector */
+	OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
+	OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
+
+	OUT_BYTE((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
+	if (handler != NULL) {
+		ide_set_handler (drive, handler, WAIT_CMD, NULL);
+		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
+	} else {
+		/* for dma commands we down set the handler */
+		if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
+	}
+}
+
+#if 0
+ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task)
+{
+	task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
+	hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister;
+	struct hd_driveid *id = drive->id;
+
+	/*
+	 * (KS) Check taskfile in/out flags.
+	 * If set, then execute as it is defined.
+	 * If not set, then define default settings.
+	 * The default values are:
+	 *	write and read all taskfile registers (except data) 
+	 *	write and read the hob registers (sector,nsector,lcyl,hcyl)
+	 */
+	if (task->tf_out_flags.all == 0) {
+		task->tf_out_flags.all = IDE_TASKFILE_STD_OUT_FLAGS;
+		if ((id->command_set_2 & 0x0400) &&
+		    (id->cfs_enable_2 & 0x0400) &&
+		    (drive->addressing == 1)) {
+			task->tf_out_flags.all != (IDE_HOB_STD_OUT_FLAGS << 8);
+		}
+        }
+
+	if (task->tf_in_flags.all == 0) {
+		task->tf_in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
+		if ((id->command_set_2 & 0x0400) &&
+		    (id->cfs_enable_2 & 0x0400) &&
+		    (drive->addressing == 1)) {
+			task->tf_in_flags.all  != (IDE_HOB_STD_IN_FLAGS  << 8);
+		}
+        }
+
+	if (IDE_CONTROL_REG)
+		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);	/* clear nIEN */
+	SELECT_MASK(HWIF(drive), drive, 0);
+
+	if (task->tf_out_flags.b.data) {
+		unsigned short data =  taskfile->data + (hobfile->data << 8);
+		OUT_WORD (data, IDE_DATA_REG);
+	}
+
+	/* (KS) send hob registers first */
+	if (task->tf_out_flags.b.nsector_hob)
+		OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG);
+	if (task->tf_out_flags.b.sector_hob)
+		OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG);
+	if (task->tf_out_flags.b.lcyl_hob)
+		OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG);
+	if (task->tf_out_flags.b.hcyl_hob)
+		OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG);
+
+
+	/* (KS) Send now the standard registers */
+	if (task->tf_out_flags.b.error_feature)
+		OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
+	/* refers to number of sectors to transfer */
+	if (task->tf_out_flags.b.nsector)
+		OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
+	/* refers to sector offset or start sector */
+	if (task->tf_out_flags.b.sector)
+		OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
+	if (task->tf_out_flags.b.lcyl)
+		OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
+	if (task->tf_out_flags.b.hcyl)
+		OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
+
+        /*
+	 * (KS) Do not modify the specified taskfile. We want to have a
+	 * universal pass through, so we must execute ALL specified values.
+	 *
+	 * (KS) The drive head register is mandatory.
+	 * Don't care about the out flags !
+	 */
+	OUT_BYTE(taskfile->device_head | drive->select.all, IDE_SELECT_REG);
+	if (task->handler != NULL) {
+		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
+		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
+		/*
+		 * warning check for race between handler and prehandler for
+		 * writing first block of data.  however since we are well
+		 * inside the boundaries of the seek, we should be okay.
+		 */
+		if (task->prehandler != NULL) {
+			return task->prehandler(drive, task->rq);
+		}
+	} else {
+		/* for dma commands we down set the handler */
+		if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
+	}
+
+	return ide_started;
+}
+#endif
+
+#if 0
+/*
+ * Error reporting, in human readable form (luxurious, but a memory hog).
+ */
+byte taskfile_dump_status (ide_drive_t *drive, const char *msg, byte stat)
+{
+	unsigned long flags;
+	byte err = 0;
+
+	__save_flags (flags);	/* local CPU only */
+	ide__sti();		/* local CPU only */
+	printk("%s: %s: status=0x%02x", drive->name, msg, stat);
+#if FANCY_STATUS_DUMPS
+	printk(" { ");
+	if (stat & BUSY_STAT)
+		printk("Busy ");
+	else {
+		if (stat & READY_STAT)	printk("DriveReady ");
+		if (stat & WRERR_STAT)	printk("DeviceFault ");
+		if (stat & SEEK_STAT)	printk("SeekComplete ");
+		if (stat & DRQ_STAT)	printk("DataRequest ");
+		if (stat & ECC_STAT)	printk("CorrectedError ");
+		if (stat & INDEX_STAT)	printk("Index ");
+		if (stat & ERR_STAT)	printk("Error ");
+	}
+	printk("}");
+#endif  /* FANCY_STATUS_DUMPS */
+	printk("\n");
+	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
+		err = GET_ERR();
+		printk("%s: %s: error=0x%02x", drive->name, msg, err);
+#if FANCY_STATUS_DUMPS
+		if (drive->media == ide_disk) {
+			printk(" { ");
+			if (err & ABRT_ERR)	printk("DriveStatusError ");
+			if (err & ICRC_ERR)	printk("%s", (err & ABRT_ERR) ? "BadCRC " : "BadSector ");
+			if (err & ECC_ERR)	printk("UncorrectableError ");
+			if (err & ID_ERR)	printk("SectorIdNotFound ");
+			if (err & TRK0_ERR)	printk("TrackZeroNotFound ");
+			if (err & MARK_ERR)	printk("AddrMarkNotFound ");
+			printk("}");
+			if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
+				if ((drive->id->command_set_2 & 0x0400) &&
+				    (drive->id->cfs_enable_2 & 0x0400) &&
+				    (drive->addressing == 1)) {
+					__u64 sectors = 0;
+					u32 low = 0, high = 0;
+					low = task_read_24(drive);
+					OUT_BYTE(0x80, IDE_CONTROL_REG);
+					high = task_read_24(drive);
+					sectors = ((__u64)high << 24) | low;
+					printk(", LBAsect=%lld", sectors);
+				} else {
+					byte cur = IN_BYTE(IDE_SELECT_REG);
+					if (cur & 0x40) {	/* using LBA? */
+						printk(", LBAsect=%ld", (unsigned long)
+						 ((cur&0xf)<<24)
+						 |(IN_BYTE(IDE_HCYL_REG)<<16)
+						 |(IN_BYTE(IDE_LCYL_REG)<<8)
+						 | IN_BYTE(IDE_SECTOR_REG));
+					} else {
+						printk(", CHS=%d/%d/%d",
+						  (IN_BYTE(IDE_HCYL_REG)<<8) +
+						   IN_BYTE(IDE_LCYL_REG),
+						  cur & 0xf,
+						  IN_BYTE(IDE_SECTOR_REG));
+					}
+				}
+				if (HWGROUP(drive)->rq)
+					printk(", sector=%llu", (__u64) HWGROUP(drive)->rq->sector);
+			}
+		}
+#endif  /* FANCY_STATUS_DUMPS */
+		printk("\n");
+	}
+	__restore_flags (flags);	/* local CPU only */
+	return err;
+}
+
+/*
+ * Clean up after success/failure of an explicit taskfile operation.
+ */
+void ide_end_taskfile (ide_drive_t *drive, byte stat, byte err)
+{
+	unsigned long flags;
+	struct request *rq;
+	ide_task_t *args;
+	task_ioreg_t command;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	rq = HWGROUP(drive)->rq;
+	spin_unlock_irqrestore(&ide_lock, flags);
+	args = (ide_task_t *) rq->special;
+
+	command = args->tfRegister[IDE_COMMAND_OFFSET];
+
+	rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+
+	args->tfRegister[IDE_ERROR_OFFSET]   = err;
+	args->tfRegister[IDE_NSECTOR_OFFSET] = IN_BYTE(IDE_NSECTOR_REG);
+	args->tfRegister[IDE_SECTOR_OFFSET]  = IN_BYTE(IDE_SECTOR_REG);
+	args->tfRegister[IDE_LCYL_OFFSET]    = IN_BYTE(IDE_LCYL_REG);
+	args->tfRegister[IDE_HCYL_OFFSET]    = IN_BYTE(IDE_HCYL_REG);
+	args->tfRegister[IDE_SELECT_OFFSET]  = IN_BYTE(IDE_SELECT_REG);
+	args->tfRegister[IDE_STATUS_OFFSET]  = stat;
+	if ((drive->id->command_set_2 & 0x0400) &&
+	    (drive->id->cfs_enable_2 & 0x0400) &&
+	    (drive->addressing == 1)) {
+		OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
+		args->hobRegister[IDE_FEATURE_OFFSET_HOB] = IN_BYTE(IDE_FEATURE_REG);
+		args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = IN_BYTE(IDE_NSECTOR_REG);
+		args->hobRegister[IDE_SECTOR_OFFSET_HOB]  = IN_BYTE(IDE_SECTOR_REG);
+		args->hobRegister[IDE_LCYL_OFFSET_HOB]    = IN_BYTE(IDE_LCYL_REG);
+		args->hobRegister[IDE_HCYL_OFFSET_HOB]    = IN_BYTE(IDE_HCYL_REG);
+	}
+
+/*	taskfile_settings_update(drive, args, command); */
+
+	spin_lock_irqsave(&ide_lock, flags);
+	blkdev_dequeue_request(rq);
+	HWGROUP(drive)->rq = NULL;
+	end_that_request_last(rq);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+/*
+ * try_to_flush_leftover_data() is invoked in response to a drive
+ * unexpectedly having its DRQ_STAT bit set.  As an alternative to
+ * resetting the drive, this routine tries to clear the condition
+ * by read a sector's worth of data from the drive.  Of course,
+ * this may not help if the drive is *waiting* for data from *us*.
+ */
+void task_try_to_flush_leftover_data (ide_drive_t *drive)
+{
+	int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS;
+
+	if (drive->media != ide_disk)
+		return;
+	while (i > 0) {
+		u32 buffer[16];
+		unsigned int wcount = (i > 16) ? 16 : i;
+		i -= wcount;
+		taskfile_input_data (drive, buffer, wcount);
+	}
+}
+
+/*
+ * taskfile_error() takes action based on the error returned by the drive.
+ */
+ide_startstop_t taskfile_error (ide_drive_t *drive, const char *msg, byte stat)
+{
+	struct request *rq;
+	byte err;
+
+        err = taskfile_dump_status(drive, msg, stat);
+	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
+		return ide_stopped;
+	/* retry only "normal" I/O: */
+	if (rq->flags & REQ_DRIVE_TASKFILE) {
+		rq->errors = 1;
+		ide_end_taskfile(drive, stat, err);
+		return ide_stopped;
+	}
+	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */
+		rq->errors |= ERROR_RESET;
+	} else {
+		if (drive->media == ide_disk && (stat & ERR_STAT)) {
+			/* err has different meaning on cdrom and tape */
+			if (err == ABRT_ERR) {
+				if (drive->select.b.lba && IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY)
+					return ide_stopped;	/* some newer drives don't support WIN_SPECIFY */
+			} else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR)) {
+				drive->crc_count++;	/* UDMA crc error -- just retry the operation */
+			} else if (err & (BBD_ERR | ECC_ERR))	/* retries won't help these */
+				rq->errors = ERROR_MAX;
+			else if (err & TRK0_ERR)	/* help it find track zero */
+				rq->errors |= ERROR_RECAL;
+		}
+		/* pre bio (rq->cmd != WRITE) */
+		if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ)
+			task_try_to_flush_leftover_data(drive);
+	}
+	if (GET_STAT() & (BUSY_STAT|DRQ_STAT))
+		OUT_BYTE(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);	/* force an abort */
+
+	if (rq->errors >= ERROR_MAX) {
+		if (drive->driver != NULL)
+			DRIVER(drive)->end_request(0, HWGROUP(drive));
+		else
+			ide_end_request(0, HWGROUP(drive));
+	} else {
+		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
+			++rq->errors;
+			return ide_do_reset(drive);
+		}
+		if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
+			drive->special.b.recalibrate = 1;
+		++rq->errors;
+	}
+	return ide_stopped;
+}
+#endif
+
+/*
+ * Handler for special commands without a data phase from ide-disk
+ */
+
+/*
+ * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
+ */
+ide_startstop_t set_multmode_intr (ide_drive_t *drive)
+{
+	byte stat;
+
+	if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT)) {
+		drive->mult_count = drive->mult_req;
+	} else {
+		drive->mult_req = drive->mult_count = 0;
+		drive->special.b.recalibrate = 1;
+		(void) ide_dump_status(drive, "set_multmode", stat);
+	}
+	return ide_stopped;
+}
+
+/*
+ * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
+ */
+ide_startstop_t set_geometry_intr (ide_drive_t *drive)
+{
+	byte stat;
+
+	if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT))
+		return ide_stopped;
+
+	if (stat & (ERR_STAT|DRQ_STAT))
+		return ide_error(drive, "set_geometry_intr", stat);
+
+	ide_set_handler(drive, &set_geometry_intr, WAIT_CMD, NULL);
+	return ide_started;
+}
+
+/*
+ * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
+ */
+ide_startstop_t recal_intr (ide_drive_t *drive)
+{
+	byte stat = GET_STAT();
+
+	if (!OK_STAT(stat,READY_STAT,BAD_STAT))
+		return ide_error(drive, "recal_intr", stat);
+	return ide_stopped;
+}
+
+/*
+ * Handler for commands without a data phase
+ */
+ide_startstop_t task_no_data_intr (ide_drive_t *drive)
+{
+	ide_task_t *args	= HWGROUP(drive)->rq->special;
+	byte stat		= GET_STAT();
+
+	ide__sti();	/* local CPU only */
+
+	if (!OK_STAT(stat, READY_STAT, BAD_STAT))
+		return ide_error(drive, "task_no_data_intr", stat);
+		/* calls ide_end_drive_cmd */
+	if (args)
+		ide_end_drive_cmd (drive, stat, GET_ERR());
+
+	return ide_stopped;
+}
+
+/*
+ * Handler for command with PIO data-in phase
+ */
+ide_startstop_t task_in_intr (ide_drive_t *drive)
+{
+	byte stat		= GET_STAT();
+	byte io_32bit		= drive->io_32bit;
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
+	unsigned long flags;
+
+	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
+		if (stat & (ERR_STAT|DRQ_STAT)) {
+			return ide_error(drive, "task_in_intr", stat);
+		}
+		if (!(stat & BUSY_STAT)) {
+			DTF("task_in_intr to Soon wait for next interrupt\n");
+			ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL);
+			return ide_started;  
+		}
+	}
+	DTF("stat: %02x\n", stat);
+	pBuf = ide_map_rq(rq, &flags);
+	DTF("Read: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors);
+
+	drive->io_32bit = 0;
+	taskfile_input_data(drive, pBuf, SECTOR_WORDS);
+	ide_unmap_rq(rq, pBuf, &flags);
+	drive->io_32bit = io_32bit;
+
+	if (--rq->current_nr_sectors <= 0) {
+		/* (hs): swapped next 2 lines */
+		DTF("Request Ended stat: %02x\n", GET_STAT());
+		if (ide_end_request(1, HWGROUP(drive))) {
+			ide_set_handler(drive, &task_in_intr,  WAIT_CMD, NULL);
+			return ide_started;
+		}
+	} else {
+		ide_set_handler(drive, &task_in_intr,  WAIT_CMD, NULL);
+		return ide_started;
+	}
+	return ide_stopped;
+}
+
+#undef ALTSTAT_SCREW_UP
+
+#ifdef ALTSTAT_SCREW_UP
+/*
+ * (ks/hs): Poll Alternate Status Register to ensure
+ * that drive is not busy.
+ */
+byte altstat_multi_busy (ide_drive_t *drive, byte stat, const char *msg)
+{
+	int i;
+
+	DTF("multi%s: ASR = %x\n", msg, stat);
+	if (stat & BUSY_STAT) {
+		/* (ks/hs): FIXME: Replace hard-coded 100, error handling? */
+		for (i=0; i<100; i++) {
+			stat = GET_ALTSTAT();
+			if ((stat & BUSY_STAT) == 0)
+				break;
+		}
+	}
+	/*
+	 * (ks/hs): Read Status AFTER Alternate Status Register
+	 */
+	return(GET_STAT());
+}
+
+/*
+ * (ks/hs): Poll Alternate status register to wait for drive
+ * to become ready for next transfer
+ */
+byte altstat_multi_poll (ide_drive_t *drive, byte stat, const char *msg)
+{
+	/* (ks/hs): FIXME: Error handling, time-out? */
+	while (stat & BUSY_STAT)
+		stat = GET_ALTSTAT();
+	DTF("multi%s: nsect=1, ASR = %x\n", msg, stat);
+	return(GET_STAT());	/* (ks/hs): Clear pending IRQ */
+}
+#endif /* ALTSTAT_SCREW_UP */
+
+/*
+ * Handler for command with Read Multiple
+ */
+ide_startstop_t task_mulin_intr (ide_drive_t *drive)
+{
+	unsigned int		msect, nsect;
+
+#ifdef ALTSTAT_SCREW_UP
+	byte stat	= altstat_multi_busy(drive, GET_ALTSTAT(), "read");
+#else
+	byte stat		= GET_STAT();
+#endif /* ALTSTAT_SCREW_UP */
+
+	byte io_32bit		= drive->io_32bit;
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
+	unsigned long flags;
+
+	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
+		if (stat & (ERR_STAT|DRQ_STAT)) {
+			return ide_error(drive, "task_mulin_intr", stat);
+		}
+		/* no data yet, so wait for another interrupt */
+		ide_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);
+		return ide_started;
+	}
+
+	/* (ks/hs): Fixed Multi-Sector transfer */
+	msect = drive->mult_count;
+
+#ifdef ALTSTAT_SCREW_UP
+	/*
+	 * Screw the request we do not support bad data-phase setups!
+	 * Either read and learn the ATA standard or crash yourself!
+	 */
+	if (!msect) {
+		/*
+		 * (ks/hs): Drive supports multi-sector transfer,
+		 * drive->mult_count was not set
+		 */
+		nsect = 1;
+		while (rq->current_nr_sectors) {
+			pBuf = ide_map_rq(rq, &flags);
+			DTF("Multiread: %p, nsect: %d, rq->current_nr_sectors: %ld\n", pBuf, nsect, rq->current_nr_sectors);
+			drive->io_32bit = 0;
+			taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
+			ide_unmap_rq(rq, pBuf, &flags);
+			drive->io_32bit = io_32bit;
+			rq->errors = 0;
+			rq->current_nr_sectors -= nsect;
+			stat = altstat_multi_poll(drive, GET_ALTSTAT(), "read");
+		}
+		ide_end_request(1, HWGROUP(drive));
+		return ide_stopped;
+	}
+#endif /* ALTSTAT_SCREW_UP */
+
+	do {
+		nsect = rq->current_nr_sectors;
+		if (nsect > msect)
+			nsect = msect;
+
+		pBuf = ide_map_rq(rq, &flags);
+
+		DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
+			pBuf, nsect, rq->current_nr_sectors);
+		drive->io_32bit = 0;
+		taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
+		ide_unmap_rq(rq, pBuf, &flags);
+		drive->io_32bit = io_32bit;
+		rq->errors = 0;
+		rq->current_nr_sectors -= nsect;
+		msect -= nsect;
+		if (!rq->current_nr_sectors) {
+			if (!ide_end_request(1, HWGROUP(drive)))
+				return ide_stopped;
+		}
+	} while (msect);
+
+
+	/*
+	 * more data left
+	 */
+	ide_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);
+	return ide_started;
+}
+
+ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
+{
+	ide_task_t *args = rq->special;
+	ide_startstop_t startstop;
+
+	if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
+		printk(KERN_ERR "%s: no DRQ after issuing %s\n", drive->name, drive->mult_count ? "MULTWRITE" : "WRITE");
+		return startstop;
+	}
+
+	/* (ks/hs): Fixed Multi Write */
+	if ((args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE) &&
+	    (args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE_EXT)) {
+		unsigned long flags;
+		char *buf = ide_map_rq(rq, &flags);
+		/* For Write_sectors we need to stuff the first sector */
+		taskfile_output_data(drive, buf, SECTOR_WORDS);
+		rq->current_nr_sectors--;
+		ide_unmap_rq(rq, buf, &flags);
+	} else {
+		/*
+		 * (ks/hs): Stuff the first sector(s)
+		 * by implicitly calling the handler
+		 */
+		if (!(drive_is_ready(drive))) {
+			int i;
+			/*
+			 * (ks/hs): FIXME: Replace hard-coded
+			 *               100, error handling?
+			 */
+			for (i=0; i<100; i++) {
+				if (drive_is_ready(drive))
+					break;
+			}
+		}
+		return args->handler(drive);
+	}
+	return ide_started;
+}
+
+/*
+ * Handler for command with PIO data-out phase
+ */
+ide_startstop_t task_out_intr (ide_drive_t *drive)
+{
+	byte stat		= GET_STAT();
+	byte io_32bit		= drive->io_32bit;
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
+	unsigned long flags;
+
+	if (!rq->current_nr_sectors) { 
+		printk("task_out_intr: should not trigger\n");
+		ide_end_request(1, HWGROUP(drive));
+		return ide_stopped;
+	}
+
+	if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) {
+		return ide_error(drive, "task_out_intr", stat);
+	}
+
+	if ((rq->current_nr_sectors==1) ^ (stat & DRQ_STAT)) {
+		rq = HWGROUP(drive)->rq;
+		pBuf = ide_map_rq(rq, &flags);
+		DTF("write: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors);
+		drive->io_32bit = 0;
+		taskfile_output_data(drive, pBuf, SECTOR_WORDS);
+		ide_unmap_rq(rq, pBuf, &flags);
+		drive->io_32bit = io_32bit;
+		rq->errors = 0;
+		rq->current_nr_sectors--;
+	}
+
+	if (rq->current_nr_sectors <= 0) {
+		if (ide_end_request(1, HWGROUP(drive))) {
+			ide_set_handler(drive, &task_out_intr, WAIT_CMD, NULL);
+			return ide_started;
+		}
+	} else {
+		ide_set_handler(drive, &task_out_intr, WAIT_CMD, NULL);
+		return ide_started;
+	}
+	return ide_stopped;
+}
+
+/*
+ * Handler for command write multiple
+ * Called directly from execute_drive_cmd for the first bunch of sectors,
+ * afterwards only by the ISR
+ */
+ide_startstop_t task_mulout_intr (ide_drive_t *drive)
+{
+	unsigned int		msect, nsect;
+
+#ifdef ALTSTAT_SCREW_UP
+	byte stat	= altstat_multi_busy(drive, GET_ALTSTAT(), "write");
+#else
+	byte stat		= GET_STAT();
+#endif /* ALTSTAT_SCREW_UP */
+
+	byte io_32bit		= drive->io_32bit;
+	struct request *rq	= HWGROUP(drive)->rq;
+	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+	char *pBuf		= NULL;
+	unsigned long flags;
+
+	/*
+	 * (ks/hs): Handle last IRQ on multi-sector transfer,
+	 * occurs after all data was sent in this chunk
+	 */
+	if (rq->current_nr_sectors == 0) {
+		if (stat & (ERR_STAT|DRQ_STAT))
+			return ide_error(drive, "task_mulout_intr", stat);
+
+		/*
+		 * there may be more, ide_do_request will restart it if
+		 * necessary
+		 */
+		ide_end_request(1, HWGROUP(drive));
+		return ide_stopped;
+	}
+
+	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
+		if (stat & (ERR_STAT|DRQ_STAT)) {
+			return ide_error(drive, "task_mulout_intr", stat);
+		}
+		/* no data yet, so wait for another interrupt */
+		if (hwgroup->handler == NULL)
+			ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
+		return ide_started;
+	}
+
+	/* (ks/hs): See task_mulin_intr */
+	msect = drive->mult_count;
+
+#ifdef ALTSTAT_SCREW_UP
+	/*
+	 * Screw the request we do not support bad data-phase setups!
+	 * Either read and learn the ATA standard or crash yourself!
+	 */
+	if (!msect) {
+		nsect = 1;
+		while (rq->current_nr_sectors) {
+			pBuf = ide_map_rq(rq, &flags);
+			DTF("Multiwrite: %p, nsect: %d, rq->current_nr_sectors: %ld\n", pBuf, nsect, rq->current_nr_sectors);
+			drive->io_32bit = 0;
+			taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+			ide_unmap_rq(pBuf, &flags);
+			drive->io_32bit = io_32bit;
+			rq->errors = 0;
+			rq->current_nr_sectors -= nsect;
+			stat = altstat_multi_poll(drive, GET_ALTSTAT(), "write");
+		}
+		ide_end_request(1, HWGROUP(drive));
+		return ide_stopped;
+	}
+#endif /* ALTSTAT_SCREW_UP */
+
+	nsect = rq->current_nr_sectors;
+	if (nsect > msect)
+		nsect = msect;
+
+	pBuf = ide_map_rq(rq, &flags);
+	DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
+		pBuf, nsect, rq->current_nr_sectors);
+	drive->io_32bit = 0;
+	taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+	ide_unmap_rq(rq, pBuf, &flags);
+	drive->io_32bit = io_32bit;
+	rq->errors = 0;
+	rq->current_nr_sectors -= nsect;
+	if (hwgroup->handler == NULL)
+		ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
+	return ide_started;
+}
+
+/* Called by internal to feature out type of command being called */
+ide_pre_handler_t * ide_pre_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile)
+{
+	switch(taskfile->command) {
+				/* IDE_DRIVE_TASK_RAW_WRITE */
+		case CFA_WRITE_MULTI_WO_ERASE:
+		case WIN_MULTWRITE:
+		case WIN_MULTWRITE_EXT:
+				/* IDE_DRIVE_TASK_OUT */
+		case WIN_WRITE:
+		case WIN_WRITE_EXT:
+		case WIN_WRITE_VERIFY:
+		case WIN_WRITE_BUFFER:
+		case CFA_WRITE_SECT_WO_ERASE:
+		case WIN_DOWNLOAD_MICROCODE:
+			return &pre_task_out_intr;
+				/* IDE_DRIVE_TASK_OUT */
+		case WIN_SMART:
+			if (taskfile->feature == SMART_WRITE_LOG_SECTOR)
+				return &pre_task_out_intr;
+		case WIN_WRITEDMA:
+		case WIN_WRITEDMA_QUEUED:
+		case WIN_WRITEDMA_EXT:
+		case WIN_WRITEDMA_QUEUED_EXT:
+				/* IDE_DRIVE_TASK_OUT */
+		default:
+			break;
+	}
+	return(NULL);
+}
+
+/* Called by internal to feature out type of command being called */
+ide_handler_t * ide_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile)
+{
+	switch(taskfile->command) {
+		case WIN_IDENTIFY:
+		case WIN_PIDENTIFY:
+		case CFA_TRANSLATE_SECTOR:
+		case WIN_READ_BUFFER:
+		case WIN_READ:
+		case WIN_READ_EXT:
+			return &task_in_intr;
+		case WIN_SECURITY_DISABLE:
+		case WIN_SECURITY_ERASE_UNIT:
+		case WIN_SECURITY_SET_PASS:
+		case WIN_SECURITY_UNLOCK:
+		case WIN_DOWNLOAD_MICROCODE:
+		case CFA_WRITE_SECT_WO_ERASE:
+		case WIN_WRITE_BUFFER:
+		case WIN_WRITE_VERIFY:
+		case WIN_WRITE:
+		case WIN_WRITE_EXT:
+			return &task_out_intr;
+		case WIN_MULTREAD:
+		case WIN_MULTREAD_EXT:
+			return &task_mulin_intr;
+		case CFA_WRITE_MULTI_WO_ERASE:
+		case WIN_MULTWRITE:
+		case WIN_MULTWRITE_EXT:
+			return &task_mulout_intr;
+		case WIN_SMART:
+			switch(taskfile->feature) {
+				case SMART_READ_VALUES:
+				case SMART_READ_THRESHOLDS:
+				case SMART_READ_LOG_SECTOR:
+					return &task_in_intr;
+				case SMART_WRITE_LOG_SECTOR:
+					return &task_out_intr;
+				default:
+					return &task_no_data_intr;
+			}
+		case CFA_REQ_EXT_ERROR_CODE:
+		case CFA_ERASE_SECTORS:
+		case WIN_VERIFY:
+		case WIN_VERIFY_EXT:
+		case WIN_SEEK:
+			return &task_no_data_intr;
+		case WIN_SPECIFY:
+			return &set_geometry_intr;
+		case WIN_RESTORE:
+			return &recal_intr;
+		case WIN_DIAGNOSE:
+		case WIN_FLUSH_CACHE:
+		case WIN_FLUSH_CACHE_EXT:
+		case WIN_STANDBYNOW1:
+		case WIN_STANDBYNOW2:
+		case WIN_SLEEPNOW1:
+		case WIN_SLEEPNOW2:
+		case WIN_SETIDLE1:
+		case WIN_CHECKPOWERMODE1:
+		case WIN_CHECKPOWERMODE2:
+		case WIN_GETMEDIASTATUS:
+		case WIN_MEDIAEJECT:
+			return &task_no_data_intr;
+		case WIN_SETMULT:
+			return &set_multmode_intr;
+		case WIN_READ_NATIVE_MAX:
+		case WIN_SET_MAX:
+		case WIN_READ_NATIVE_MAX_EXT:
+		case WIN_SET_MAX_EXT:
+		case WIN_SECURITY_ERASE_PREPARE:
+		case WIN_SECURITY_FREEZE_LOCK:
+		case WIN_DOORLOCK:
+		case WIN_DOORUNLOCK:
+		case WIN_SETFEATURES:
+			return &task_no_data_intr;
+		case DISABLE_SEAGATE:
+		case EXABYTE_ENABLE_NEST:
+			return &task_no_data_intr;
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case WIN_READDMA:
+		case WIN_IDENTIFY_DMA:
+		case WIN_READDMA_QUEUED:
+		case WIN_READDMA_EXT:
+		case WIN_READDMA_QUEUED_EXT:
+		case WIN_WRITEDMA:
+		case WIN_WRITEDMA_QUEUED:
+		case WIN_WRITEDMA_EXT:
+		case WIN_WRITEDMA_QUEUED_EXT:
+#endif
+		case WIN_FORMAT:
+		case WIN_INIT:
+		case WIN_DEVICE_RESET:
+		case WIN_QUEUED_SERVICE:
+		case WIN_PACKETCMD:
+		default:
+			return(NULL);
+	}	
+}
+
+/* Called by ioctl to feature out type of command being called */
+int ide_cmd_type_parser (ide_task_t *args)
+{
+	struct hd_drive_task_hdr *taskfile = (struct hd_drive_task_hdr *) args->tfRegister;
+	struct hd_drive_hob_hdr *hobfile = (struct hd_drive_hob_hdr *) args->hobRegister;
+
+	args->prehandler = ide_pre_handler_parser(taskfile, hobfile);
+	args->handler = ide_handler_parser(taskfile, hobfile);
+
+	switch(args->tfRegister[IDE_COMMAND_OFFSET]) {
+		case WIN_IDENTIFY:
+		case WIN_PIDENTIFY:
+			return IDE_DRIVE_TASK_IN;
+		case CFA_TRANSLATE_SECTOR:
+		case WIN_READ:
+		case WIN_READ_EXT:
+		case WIN_READ_BUFFER:
+			return IDE_DRIVE_TASK_IN;
+		case WIN_WRITE:
+		case WIN_WRITE_EXT:
+		case WIN_WRITE_VERIFY:
+		case WIN_WRITE_BUFFER:
+		case CFA_WRITE_SECT_WO_ERASE:
+		case WIN_DOWNLOAD_MICROCODE:
+			return IDE_DRIVE_TASK_RAW_WRITE;
+		case WIN_MULTREAD:
+		case WIN_MULTREAD_EXT:
+			return IDE_DRIVE_TASK_IN;
+		case CFA_WRITE_MULTI_WO_ERASE:
+		case WIN_MULTWRITE:
+		case WIN_MULTWRITE_EXT:
+			return IDE_DRIVE_TASK_RAW_WRITE;
+		case WIN_SECURITY_DISABLE:
+		case WIN_SECURITY_ERASE_UNIT:
+		case WIN_SECURITY_SET_PASS:
+		case WIN_SECURITY_UNLOCK:
+			return IDE_DRIVE_TASK_OUT;
+		case WIN_SMART:
+			args->tfRegister[IDE_LCYL_OFFSET] = SMART_LCYL_PASS;
+			args->tfRegister[IDE_HCYL_OFFSET] = SMART_HCYL_PASS;
+			switch(args->tfRegister[IDE_FEATURE_OFFSET]) {
+				case SMART_READ_VALUES:
+				case SMART_READ_THRESHOLDS:
+				case SMART_READ_LOG_SECTOR:
+					return IDE_DRIVE_TASK_IN;
+				case SMART_WRITE_LOG_SECTOR:
+					return IDE_DRIVE_TASK_OUT;
+				default:
+					return IDE_DRIVE_TASK_NO_DATA;
+			}
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case WIN_READDMA:
+		case WIN_IDENTIFY_DMA:
+		case WIN_READDMA_QUEUED:
+		case WIN_READDMA_EXT:
+		case WIN_READDMA_QUEUED_EXT:
+			return IDE_DRIVE_TASK_IN;
+		case WIN_WRITEDMA:
+		case WIN_WRITEDMA_QUEUED:
+		case WIN_WRITEDMA_EXT:
+		case WIN_WRITEDMA_QUEUED_EXT:
+			return IDE_DRIVE_TASK_RAW_WRITE;
+#endif
+		case WIN_SETFEATURES:
+			switch(args->tfRegister[IDE_FEATURE_OFFSET]) {
+				case SETFEATURES_XFER:
+					return IDE_DRIVE_TASK_SET_XFER;
+				case SETFEATURES_DIS_DEFECT:
+				case SETFEATURES_EN_APM:
+				case SETFEATURES_DIS_MSN:
+				case SETFEATURES_EN_RI:
+				case SETFEATURES_EN_SI:
+				case SETFEATURES_DIS_RPOD:
+				case SETFEATURES_DIS_WCACHE:
+				case SETFEATURES_EN_DEFECT:
+				case SETFEATURES_DIS_APM:
+				case SETFEATURES_EN_MSN:
+				case SETFEATURES_EN_RLA:
+				case SETFEATURES_PREFETCH:
+				case SETFEATURES_EN_RPOD:
+				case SETFEATURES_DIS_RI:
+				case SETFEATURES_DIS_SI:
+				default:
+					return IDE_DRIVE_TASK_NO_DATA;
+			}
+		case WIN_NOP:
+		case CFA_REQ_EXT_ERROR_CODE:
+		case CFA_ERASE_SECTORS:
+		case WIN_VERIFY:
+		case WIN_VERIFY_EXT:
+		case WIN_SEEK:
+		case WIN_SPECIFY:
+		case WIN_RESTORE:
+		case WIN_DIAGNOSE:
+		case WIN_FLUSH_CACHE:
+		case WIN_FLUSH_CACHE_EXT:
+		case WIN_STANDBYNOW1:
+		case WIN_STANDBYNOW2:
+		case WIN_SLEEPNOW1:
+		case WIN_SLEEPNOW2:
+		case WIN_SETIDLE1:
+		case DISABLE_SEAGATE:
+		case WIN_CHECKPOWERMODE1:
+		case WIN_CHECKPOWERMODE2:
+		case WIN_GETMEDIASTATUS:
+		case WIN_MEDIAEJECT:
+		case WIN_SETMULT:
+		case WIN_READ_NATIVE_MAX:
+		case WIN_SET_MAX:
+		case WIN_READ_NATIVE_MAX_EXT:
+		case WIN_SET_MAX_EXT:
+		case WIN_SECURITY_ERASE_PREPARE:
+		case WIN_SECURITY_FREEZE_LOCK:
+		case EXABYTE_ENABLE_NEST:
+		case WIN_DOORLOCK:
+		case WIN_DOORUNLOCK:
+			return IDE_DRIVE_TASK_NO_DATA;
+		case WIN_FORMAT:
+		case WIN_INIT:
+		case WIN_DEVICE_RESET:
+		case WIN_QUEUED_SERVICE:
+		case WIN_PACKETCMD:
+		default:
+			return IDE_DRIVE_TASK_INVALID;
+	}
+}
+
+/*
+ * This function is intended to be used prior to invoking ide_do_drive_cmd().
+ */
+void ide_init_drive_taskfile (struct request *rq)
+{
+	memset(rq, 0, sizeof(*rq));
+	rq->flags = REQ_DRIVE_TASKFILE;
+}
+
+/*
+ * This is kept for internal use only !!!
+ * This is an internal call and nobody in user-space has a damn
+ * reason to call this taskfile.
+ *
+ * ide_raw_taskfile is the one that user-space executes.
+ */
+int ide_wait_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, byte *buf)
+{
+	struct request rq;
+	ide_task_t args;
+
+	memset(&args, 0, sizeof(ide_task_t));
+
+	args.tfRegister[IDE_DATA_OFFSET]         = taskfile->data;
+	args.tfRegister[IDE_FEATURE_OFFSET]      = taskfile->feature;
+	args.tfRegister[IDE_NSECTOR_OFFSET]      = taskfile->sector_count;
+	args.tfRegister[IDE_SECTOR_OFFSET]       = taskfile->sector_number;
+	args.tfRegister[IDE_LCYL_OFFSET]         = taskfile->low_cylinder;
+	args.tfRegister[IDE_HCYL_OFFSET]         = taskfile->high_cylinder;
+	args.tfRegister[IDE_SELECT_OFFSET]       = taskfile->device_head;
+	args.tfRegister[IDE_COMMAND_OFFSET]      = taskfile->command;
+
+	args.hobRegister[IDE_DATA_OFFSET_HOB]    = hobfile->data;
+	args.hobRegister[IDE_FEATURE_OFFSET_HOB] = hobfile->feature;
+	args.hobRegister[IDE_NSECTOR_OFFSET_HOB] = hobfile->sector_count;
+	args.hobRegister[IDE_SECTOR_OFFSET_HOB]  = hobfile->sector_number;
+	args.hobRegister[IDE_LCYL_OFFSET_HOB]    = hobfile->low_cylinder;
+	args.hobRegister[IDE_HCYL_OFFSET_HOB]    = hobfile->high_cylinder;
+	args.hobRegister[IDE_SELECT_OFFSET_HOB]  = hobfile->device_head;
+	args.hobRegister[IDE_CONTROL_OFFSET_HOB] = hobfile->control;
+
+	ide_init_drive_taskfile(&rq);
+	/* This is kept for internal use only !!! */
+	args.command_type = ide_cmd_type_parser (&args);
+	if (args.command_type != IDE_DRIVE_TASK_NO_DATA)
+		rq.current_nr_sectors = rq.nr_sectors = (hobfile->sector_count << 8) | taskfile->sector_count;
+
+	rq.buffer = buf;
+	rq.special = &args;
+	return ide_do_drive_cmd(drive, &rq, ide_wait);
+}
+
+int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, byte *buf)
+{
+	struct request rq;
+	ide_init_drive_taskfile(&rq);
+	rq.buffer = buf;
+
+	if (args->command_type != IDE_DRIVE_TASK_NO_DATA)
+		rq.current_nr_sectors = rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET_HOB] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET];
+
+	rq.special = args;
+	return ide_do_drive_cmd(drive, &rq, ide_wait);
+}
+
+
+#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
+char * ide_ioctl_verbose (unsigned int cmd)
+{
+	return("unknown");
+}
+
+char * ide_task_cmd_verbose (byte task)
+{
+	return("unknown");
+}
+#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
+
+/*
+ *  The taskfile glue table
+ *
+ *  reqtask.data_phase	reqtask.req_cmd
+ *  			args.command_type		args.handler
+ *
+ *  TASKFILE_P_OUT_DMAQ	??				??
+ *  TASKFILE_P_IN_DMAQ	??				??
+ *  TASKFILE_P_OUT_DMA	??				??
+ *  TASKFILE_P_IN_DMA	??				??
+ *  TASKFILE_P_OUT	??				??
+ *  TASKFILE_P_IN	??				??
+ *
+ *  TASKFILE_OUT_DMAQ	IDE_DRIVE_TASK_RAW_WRITE	NULL
+ *  TASKFILE_IN_DMAQ	IDE_DRIVE_TASK_IN		NULL
+ *
+ *  TASKFILE_OUT_DMA	IDE_DRIVE_TASK_RAW_WRITE	NULL
+ *  TASKFILE_IN_DMA	IDE_DRIVE_TASK_IN		NULL
+ *
+ *  TASKFILE_IN_OUT	??				??
+ *
+ *  TASKFILE_MULTI_OUT	IDE_DRIVE_TASK_RAW_WRITE	task_mulout_intr
+ *  TASKFILE_MULTI_IN	IDE_DRIVE_TASK_IN		task_mulin_intr
+ *
+ *  TASKFILE_OUT	IDE_DRIVE_TASK_RAW_WRITE	task_out_intr
+ *  TASKFILE_OUT	IDE_DRIVE_TASK_OUT		task_out_intr
+ *
+ *  TASKFILE_IN		IDE_DRIVE_TASK_IN		task_in_intr
+ *  TASKFILE_NO_DATA	IDE_DRIVE_TASK_NO_DATA		task_no_data_intr
+ *
+ *  			IDE_DRIVE_TASK_SET_XFER		task_no_data_intr
+ *  			IDE_DRIVE_TASK_INVALID
+ *
+ */
+
+#define MAX_DMA		(256*SECTOR_WORDS)
+
+int ide_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	ide_task_request_t	*req_task;
+	ide_task_t		args;
+
+	byte *outbuf		= NULL;
+	byte *inbuf		= NULL;
+	task_ioreg_t *argsptr	= args.tfRegister;
+	task_ioreg_t *hobsptr	= args.hobRegister;
+	int err			= 0;
+	int tasksize		= sizeof(struct ide_task_request_s);
+	int taskin		= 0;
+	int taskout		= 0;
+
+	req_task = kmalloc(tasksize, GFP_KERNEL);
+	if (req_task == NULL) return -ENOMEM;
+	memset(req_task, 0, tasksize);
+	if (copy_from_user(req_task, (void *) arg, tasksize)) {
+		kfree(req_task);
+		return -EFAULT;
+	}
+
+	taskout = (int) req_task->out_size;
+	taskin  = (int) req_task->in_size;
+
+	if (taskout) {
+		int outtotal = tasksize;
+		outbuf = kmalloc(taskout, GFP_KERNEL);
+		if (outbuf == NULL) {
+			err = -ENOMEM;
+			goto abort;
+		}
+		memset(outbuf, 0, taskout);
+		if (copy_from_user(outbuf, (void *)arg + outtotal, taskout)) {
+			err = -EFAULT;
+			goto abort;
+		}
+	}
+
+	if (taskin) {
+		int intotal = tasksize + taskout;
+		inbuf = kmalloc(taskin, GFP_KERNEL);
+		if (inbuf == NULL) {
+			err = -ENOMEM;
+			goto abort;
+		}
+		memset(inbuf, 0, taskin);
+		if (copy_from_user(inbuf, (void *)arg + intotal , taskin)) {
+			err = -EFAULT;
+			goto abort;
+		}
+	}
+
+	memset(argsptr, 0, HDIO_DRIVE_TASK_HDR_SIZE);
+	memset(hobsptr, 0, HDIO_DRIVE_HOB_HDR_SIZE);
+	memcpy(argsptr, req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE);
+	memcpy(hobsptr, req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE);
+
+	args.tf_in_flags  = req_task->in_flags;
+	args.tf_out_flags = req_task->out_flags;
+	args.data_phase   = req_task->data_phase;
+	args.command_type = req_task->req_cmd;
+
+#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
+	DTF("%s: ide_ioctl_cmd %s:  ide_task_cmd %s\n",
+		drive->name,
+		ide_ioctl_verbose(cmd),
+		ide_task_cmd_verbose(args.tfRegister[IDE_COMMAND_OFFSET]));
+#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
+
+	switch(req_task->data_phase) {
+		case TASKFILE_OUT_DMAQ:
+		case TASKFILE_OUT_DMA:
+			args.prehandler = NULL;
+			args.handler = NULL;
+			args.posthandler = NULL;
+			err = ide_raw_taskfile(drive, &args, outbuf);
+			break;
+		case TASKFILE_IN_DMAQ:
+		case TASKFILE_IN_DMA:
+			args.prehandler = NULL;
+			args.handler = NULL;
+			args.posthandler = NULL;
+			err = ide_raw_taskfile(drive, &args, inbuf);
+			break;
+		case TASKFILE_IN_OUT:
+#if 0
+			args.prehandler = &pre_task_out_intr;
+			args.handler = &task_out_intr;
+			args.posthandler = NULL;
+			err = ide_raw_taskfile(drive, &args, outbuf);
+			args.prehandler = NULL;
+			args.handler = &task_in_intr;
+			args.posthandler = NULL;
+			err = ide_raw_taskfile(drive, &args, inbuf);
+			break;
+#else
+			err = -EFAULT;
+			goto abort;
+#endif
+		case TASKFILE_MULTI_OUT:
+			if (drive->mult_count) {
+				args.prehandler = &pre_task_out_intr;
+				args.handler = &task_mulout_intr;
+				args.posthandler = NULL;
+				err = ide_raw_taskfile(drive, &args, outbuf);
+			} else {
+				/* (hs): give up if multcount is not set */
+				printk("%s: %s Multimode Write " \
+					"multcount is not set\n",
+					 drive->name, __FUNCTION__);
+				err = -EPERM;
+				goto abort;
+			}
+			break;
+		case TASKFILE_OUT:
+			args.prehandler = &pre_task_out_intr;
+			args.handler = &task_out_intr;
+			args.posthandler = NULL;
+			err = ide_raw_taskfile(drive, &args, outbuf);
+			break;
+		case TASKFILE_MULTI_IN:
+			if (drive->mult_count) {
+				args.prehandler = NULL;
+				args.handler = &task_mulin_intr;
+				args.posthandler = NULL;
+				err = ide_raw_taskfile(drive, &args, inbuf);
+			} else {
+				/* (hs): give up if multcount is not set */
+				printk("%s: %s Multimode Read failure " \
+					"multcount is not set\n",
+					drive->name, __FUNCTION__);
+				err = -EPERM;
+				goto abort;
+			}
+			break;
+		case TASKFILE_IN:
+			args.prehandler = NULL;
+			args.handler = &task_in_intr;
+			args.posthandler = NULL;
+			err = ide_raw_taskfile(drive, &args, inbuf);
+			break;
+		case TASKFILE_NO_DATA:
+			args.prehandler = NULL;
+			args.handler = &task_no_data_intr;
+			args.posthandler = NULL;
+			err = ide_raw_taskfile(drive, &args, NULL);
+			break;
+		default:
+			args.prehandler = NULL;
+			args.handler = NULL;
+			args.posthandler = NULL;
+			err = -EFAULT;
+			goto abort;
+	}
+
+	memcpy(req_task->io_ports, &(args.tfRegister), HDIO_DRIVE_TASK_HDR_SIZE);
+	memcpy(req_task->hob_ports, &(args.hobRegister), HDIO_DRIVE_HOB_HDR_SIZE);
+	req_task->in_flags  = args.tf_in_flags;
+	req_task->out_flags = args.tf_out_flags;
+
+	if (copy_to_user((void *)arg, req_task, tasksize)) {
+		err = -EFAULT;
+		goto abort;
+	}
+	if (taskout) {
+		int outtotal = tasksize;
+		if (copy_to_user((void *)arg+outtotal, outbuf, taskout)) {
+			err = -EFAULT;
+			goto abort;
+		}
+	}
+	if (taskin) {
+		int intotal = tasksize + taskout;
+		if (copy_to_user((void *)arg+intotal, inbuf, taskin)) {
+			err = -EFAULT;
+			goto abort;
+		}
+	}
+abort:
+	kfree(req_task);
+	if (outbuf != NULL)
+		kfree(outbuf);
+	if (inbuf != NULL)
+		kfree(inbuf);
+	return err;
+}
+
+int ide_cmd_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int err = 0;
+	byte args[4], *argbuf = args;
+	byte xfer_rate = 0;
+	int argsize = 4;
+	ide_task_t tfargs;
+
+	if (NULL == (void *) arg) {
+		struct request rq;
+		ide_init_drive_cmd(&rq);
+		return ide_do_drive_cmd(drive, &rq, ide_wait);
+	}
+	if (copy_from_user(args, (void *)arg, 4))
+		return -EFAULT;
+
+	tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2];
+	tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3];
+	tfargs.tfRegister[IDE_SECTOR_OFFSET]  = args[1];
+	tfargs.tfRegister[IDE_LCYL_OFFSET]    = 0x00;
+	tfargs.tfRegister[IDE_HCYL_OFFSET]    = 0x00;
+	tfargs.tfRegister[IDE_SELECT_OFFSET]  = 0x00;
+	tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0];
+
+	if (args[3]) {
+		argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
+		argbuf = kmalloc(argsize, GFP_KERNEL);
+		if (argbuf == NULL)
+			return -ENOMEM;
+		memcpy(argbuf, args, 4);
+	}
+	if (set_transfer(drive, &tfargs)) {
+		xfer_rate = args[1];
+		if (ide_ata66_check(drive, &tfargs))
+			goto abort;
+	}
+
+	err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
+
+	if (!err && xfer_rate) {
+		/* active-retuning-calls future */
+		if ((HWIF(drive)->speedproc) != NULL)
+			HWIF(drive)->speedproc(drive, xfer_rate);
+		ide_driveid_update(drive);
+	}
+abort:
+	if (copy_to_user((void *)arg, argbuf, argsize))
+		err = -EFAULT;
+	if (argsize > 4)
+		kfree(argbuf);
+	return err;
+}
+
+int ide_task_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int err = 0;
+	byte args[7], *argbuf = args;
+	int argsize = 7;
+
+	if (copy_from_user(args, (void *)arg, 7))
+		return -EFAULT;
+	err = ide_wait_cmd_task(drive, argbuf);
+	if (copy_to_user((void *)arg, argbuf, argsize))
+		err = -EFAULT;
+	return err;
+}
+
+EXPORT_SYMBOL(drive_is_ready);
+EXPORT_SYMBOL(task_read_24);
+EXPORT_SYMBOL(ata_input_data);
+EXPORT_SYMBOL(ata_output_data);
+EXPORT_SYMBOL(atapi_input_bytes);
+EXPORT_SYMBOL(atapi_output_bytes);
+EXPORT_SYMBOL(taskfile_input_data);
+EXPORT_SYMBOL(taskfile_output_data);
+EXPORT_SYMBOL(do_rw_taskfile);
+EXPORT_SYMBOL(do_taskfile);
+// EXPORT_SYMBOL(flagged_taskfile);
+
+//EXPORT_SYMBOL(ide_end_taskfile);
+
+EXPORT_SYMBOL(set_multmode_intr);
+EXPORT_SYMBOL(set_geometry_intr);
+EXPORT_SYMBOL(recal_intr);
+
+EXPORT_SYMBOL(task_no_data_intr);
+EXPORT_SYMBOL(task_in_intr);
+EXPORT_SYMBOL(task_mulin_intr);
+EXPORT_SYMBOL(pre_task_out_intr);
+EXPORT_SYMBOL(task_out_intr);
+EXPORT_SYMBOL(task_mulout_intr);
+
+EXPORT_SYMBOL(ide_init_drive_taskfile);
+EXPORT_SYMBOL(ide_wait_taskfile);
+EXPORT_SYMBOL(ide_raw_taskfile);
+EXPORT_SYMBOL(ide_pre_handler_parser);
+EXPORT_SYMBOL(ide_handler_parser);
+EXPORT_SYMBOL(ide_cmd_type_parser);
+EXPORT_SYMBOL(ide_taskfile_ioctl);
+EXPORT_SYMBOL(ide_cmd_ioctl);
+EXPORT_SYMBOL(ide_task_ioctl);
+
+
+#ifdef CONFIG_PKT_TASK_IOCTL
+
+#if 0
+{
+
+{ /* start cdrom */
+
+	struct cdrom_info *info = drive->driver_data;
+
+	if (info->dma) {
+		if (info->cmd == READ) {
+			info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive);
+		} else if (info->cmd == WRITE) {
+			info->dma = !HWIF(drive)->dmaproc(ide_dma_write, drive);
+		} else {
+			printk("ide-cd: DMA set, but not allowed\n");
+		}
+	}
+
+	/* Set up the controller registers. */
+	OUT_BYTE (info->dma, IDE_FEATURE_REG);
+	OUT_BYTE (0, IDE_NSECTOR_REG);
+	OUT_BYTE (0, IDE_SECTOR_REG);
+
+	OUT_BYTE (xferlen & 0xff, IDE_LCYL_REG);
+	OUT_BYTE (xferlen >> 8  , IDE_HCYL_REG);
+	if (IDE_CONTROL_REG)
+		OUT_BYTE (drive->ctl, IDE_CONTROL_REG);
+
+	if (info->dma)
+		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+
+	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
+		ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry);
+		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
+		return ide_started;
+	} else {
+		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
+		return (*handler) (drive);
+	}
+
+} /* end cdrom */
+
+{ /* start floppy */
+
+	idefloppy_floppy_t *floppy = drive->driver_data;
+	idefloppy_bcount_reg_t bcount;
+	int dma_ok = 0;
+
+	floppy->pc=pc;		/* Set the current packet command */
+
+	pc->retries++;
+	pc->actually_transferred=0; /* We haven't transferred any data yet */
+	pc->current_position=pc->buffer;
+	bcount.all = IDE_MIN(pc->request_transfer, 63 * 1024);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
+		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+	}
+	if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
+		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+	if (IDE_CONTROL_REG)
+		OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
+	OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG);	/* Use PIO/DMA */
+	OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG);
+	OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG);
+	OUT_BYTE (drive->select.all,IDE_SELECT_REG);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (dma_ok) {	/* Begin DMA, if necessary */
+		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
+		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+} /* end floppy */
+
+{ /* start tape */
+
+	idetape_tape_t *tape = drive->driver_data;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
+		printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n");
+		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+	}
+	if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
+		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+	if (IDE_CONTROL_REG)
+		OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
+	OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG);	/* Use PIO/DMA */
+	OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG);
+	OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG);
+	OUT_BYTE (drive->select.all,IDE_SELECT_REG);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (dma_ok) {	/* Begin DMA, if necessary */
+		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
+		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
+		ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL);
+		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
+		return ide_started;
+	} else {
+		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
+		return idetape_transfer_pc(drive);
+	}
+
+} /* end tape */
+
+}
+#endif
+
+int pkt_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+#if 0
+	switch(req_task->data_phase) {
+		case TASKFILE_P_OUT_DMAQ:
+		case TASKFILE_P_IN_DMAQ:
+		case TASKFILE_P_OUT_DMA:
+		case TASKFILE_P_IN_DMA:
+		case TASKFILE_P_OUT:
+		case TASKFILE_P_IN:
+	}
+#endif
+	return -ENOMSG;
+}
+
+EXPORT_SYMBOL(pkt_taskfile_ioctl);
+
+#endif /* CONFIG_PKT_TASK_IOCTL */
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/ide.c linux/drivers/ide/ide.c
--- v2.5.2/linux/drivers/ide/ide.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/ide/ide.c	Thu Jan 17 13:58:35 2002
@@ -151,6 +151,7 @@
 #include <linux/ide.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/completion.h>
+#include <linux/reboot.h>
 #include <linux/cdrom.h>
 
 #include <asm/byteorder.h>
@@ -371,186 +372,6 @@
 	return system_bus_speed;
 }
 
-#if SUPPORT_VLB_SYNC
-/*
- * Some localbus EIDE interfaces require a special access sequence
- * when using 32-bit I/O instructions to transfer data.  We call this
- * the "vlb_sync" sequence, which consists of three successive reads
- * of the sector count register location, with interrupts disabled
- * to ensure that the reads all happen together.
- */
-static inline void do_vlb_sync (ide_ioreg_t port) {
-	(void) inb (port);
-	(void) inb (port);
-	(void) inb (port);
-}
-#endif /* SUPPORT_VLB_SYNC */
-
-/*
- * This is used for most PIO data transfers *from* the IDE interface
- */
-void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
-{
-	byte io_32bit;
-
-	/* first check if this controller has defined a special function
-	 * for handling polled ide transfers
-	 */
-
-	if(HWIF(drive)->ideproc) {
-		HWIF(drive)->ideproc(ideproc_ide_input_data,
-				     drive, buffer, wcount);
-		return;
-	}
-
-	io_32bit = drive->io_32bit;
-
-	if (io_32bit) {
-#if SUPPORT_VLB_SYNC
-		if (io_32bit & 2) {
-			unsigned long flags;
-			__save_flags(flags);	/* local CPU only */
-			__cli();		/* local CPU only */
-			do_vlb_sync(IDE_NSECTOR_REG);
-			insl(IDE_DATA_REG, buffer, wcount);
-			__restore_flags(flags);	/* local CPU only */
-		} else
-#endif /* SUPPORT_VLB_SYNC */
-			insl(IDE_DATA_REG, buffer, wcount);
-	} else {
-#if SUPPORT_SLOW_DATA_PORTS
-		if (drive->slow) {
-			unsigned short *ptr = (unsigned short *) buffer;
-			while (wcount--) {
-				*ptr++ = inw_p(IDE_DATA_REG);
-				*ptr++ = inw_p(IDE_DATA_REG);
-			}
-		} else
-#endif /* SUPPORT_SLOW_DATA_PORTS */
-			insw(IDE_DATA_REG, buffer, wcount<<1);
-	}
-}
-
-/*
- * This is used for most PIO data transfers *to* the IDE interface
- */
-void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
-{
-	byte io_32bit;
-
-	if(HWIF(drive)->ideproc) {
-		HWIF(drive)->ideproc(ideproc_ide_output_data,
-				     drive, buffer, wcount);
-		return;
-	}
-
-	io_32bit = drive->io_32bit;
-
-	if (io_32bit) {
-#if SUPPORT_VLB_SYNC
-		if (io_32bit & 2) {
-			unsigned long flags;
-			__save_flags(flags);	/* local CPU only */
-			__cli();		/* local CPU only */
-			do_vlb_sync(IDE_NSECTOR_REG);
-			outsl(IDE_DATA_REG, buffer, wcount);
-			__restore_flags(flags);	/* local CPU only */
-		} else
-#endif /* SUPPORT_VLB_SYNC */
-			outsl(IDE_DATA_REG, buffer, wcount);
-	} else {
-#if SUPPORT_SLOW_DATA_PORTS
-		if (drive->slow) {
-			unsigned short *ptr = (unsigned short *) buffer;
-			while (wcount--) {
-				outw_p(*ptr++, IDE_DATA_REG);
-				outw_p(*ptr++, IDE_DATA_REG);
-			}
-		} else
-#endif /* SUPPORT_SLOW_DATA_PORTS */
-			outsw(IDE_DATA_REG, buffer, wcount<<1);
-	}
-}
-
-/*
- * The following routines are mainly used by the ATAPI drivers.
- *
- * These routines will round up any request for an odd number of bytes,
- * so if an odd bytecount is specified, be sure that there's at least one
- * extra byte allocated for the buffer.
- */
-void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
-{
-	if(HWIF(drive)->ideproc) {
-		HWIF(drive)->ideproc(ideproc_atapi_input_bytes,
-				     drive, buffer, bytecount);
-		return;
-	}
-
-	++bytecount;
-#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
-	if (MACH_IS_ATARI || MACH_IS_Q40) {
-		/* Atari has a byte-swapped IDE interface */
-		insw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
-		return;
-	}
-#endif /* CONFIG_ATARI */
-	ide_input_data (drive, buffer, bytecount / 4);
-	if ((bytecount & 0x03) >= 2)
-		insw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);
-}
-
-void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
-{
-	if(HWIF(drive)->ideproc) {
-		HWIF(drive)->ideproc(ideproc_atapi_output_bytes,
-				     drive, buffer, bytecount);
-		return;
-	}
-
-	++bytecount;
-#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
-	if (MACH_IS_ATARI || MACH_IS_Q40) {
-		/* Atari has a byte-swapped IDE interface */
-		outsw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
-		return;
-	}
-#endif /* CONFIG_ATARI */
-	ide_output_data (drive, buffer, bytecount / 4);
-	if ((bytecount & 0x03) >= 2)
-		outsw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);
-}
-
-/*
- * Needed for PCI irq sharing
- */
-static inline int drive_is_ready (ide_drive_t *drive)
-{
-	byte stat = 0;
-	if (drive->waiting_for_dma)
-		return HWIF(drive)->dmaproc(ide_dma_test_irq, drive);
-#if 0
-	udelay(1);	/* need to guarantee 400ns since last command was issued */
-#endif
-
-#ifdef CONFIG_IDEPCI_SHARE_IRQ
-	/*
-	 * We do a passive status test under shared PCI interrupts on
-	 * cards that truly share the ATA side interrupt, but may also share
-	 * an interrupt with another pci card/device.  We make no assumptions
-	 * about possible isa-pnp and pci-pnp issues yet.
-	 */
-	if (IDE_CONTROL_REG)
-		stat = GET_ALTSTAT();
-	else
-#endif /* CONFIG_IDEPCI_SHARE_IRQ */
-	stat = GET_STAT();	/* Note: this may clear a pending IRQ!! */
-
-	if (stat & BUSY_STAT)
-		return 0;	/* drive busy:  definitely not interrupting */
-	return 1;		/* drive ready: *might* be interrupting */
-}
-
 inline int __ide_end_request(ide_hwgroup_t *hwgroup, int uptodate, int nr_secs)
 {
 	ide_drive_t *drive = hwgroup->drive;
@@ -836,7 +657,11 @@
 	 */
 	OUT_BYTE(drive->ctl|6,IDE_CONTROL_REG);	/* set SRST and nIEN */
 	udelay(10);			/* more than enough time */
-	OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG);	/* clear SRST, leave nIEN */
+	if (drive->quirk_list == 2) {
+		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* clear SRST and nIEN */
+	} else {
+		OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG);	/* clear SRST, leave nIEN */
+	}
 	udelay(10);			/* more than enough time */
 	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
 	ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL);
@@ -863,6 +688,13 @@
 	return do_reset1 (drive, 0);
 }
 
+static inline u32 read_24 (ide_drive_t *drive)
+{
+	return  (IN_BYTE(IDE_HCYL_REG)<<16) |
+		(IN_BYTE(IDE_LCYL_REG)<<8) |
+		 IN_BYTE(IDE_SECTOR_REG);
+}
+
 /*
  * Clean up after success/failure of an explicit drive cmd
  */
@@ -894,6 +726,33 @@
 			args[5] = IN_BYTE(IDE_HCYL_REG);
 			args[6] = IN_BYTE(IDE_SELECT_REG);
 		}
+	} else if (rq->flags & REQ_DRIVE_TASKFILE) {
+		ide_task_t *args = (ide_task_t *) rq->special;
+		rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+		if (args) {
+			if (args->tf_in_flags.b.data) {
+				unsigned short data			= IN_WORD(IDE_DATA_REG);
+				args->tfRegister[IDE_DATA_OFFSET]	= (data) & 0xFF;
+				args->hobRegister[IDE_DATA_OFFSET_HOB]	= (data >> 8) & 0xFF;
+			}
+			args->tfRegister[IDE_ERROR_OFFSET]   = err;
+			args->tfRegister[IDE_NSECTOR_OFFSET] = IN_BYTE(IDE_NSECTOR_REG);
+			args->tfRegister[IDE_SECTOR_OFFSET]  = IN_BYTE(IDE_SECTOR_REG);
+			args->tfRegister[IDE_LCYL_OFFSET]    = IN_BYTE(IDE_LCYL_REG);
+			args->tfRegister[IDE_HCYL_OFFSET]    = IN_BYTE(IDE_HCYL_REG);
+			args->tfRegister[IDE_SELECT_OFFSET]  = IN_BYTE(IDE_SELECT_REG);
+			args->tfRegister[IDE_STATUS_OFFSET]  = stat;
+			if ((drive->id->command_set_2 & 0x0400) &&
+			    (drive->id->cfs_enable_2 & 0x0400) &&
+			    (drive->addressing == 1)) {
+				OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
+				args->hobRegister[IDE_FEATURE_OFFSET_HOB] = IN_BYTE(IDE_FEATURE_REG);
+				args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = IN_BYTE(IDE_NSECTOR_REG);
+				args->hobRegister[IDE_SECTOR_OFFSET_HOB]  = IN_BYTE(IDE_SECTOR_REG);
+				args->hobRegister[IDE_LCYL_OFFSET_HOB]    = IN_BYTE(IDE_LCYL_REG);
+				args->hobRegister[IDE_HCYL_OFFSET_HOB]    = IN_BYTE(IDE_HCYL_REG);
+			}
+		}
 	}
 
 	blkdev_dequeue_request(rq);
@@ -944,19 +803,32 @@
 			if (err & MARK_ERR)	printk("AddrMarkNotFound ");
 			printk("}");
 			if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
-				byte cur = IN_BYTE(IDE_SELECT_REG);
-				if (cur & 0x40) {	/* using LBA? */
-					printk(", LBAsect=%ld", (unsigned long)
-					 ((cur&0xf)<<24)
-					 |(IN_BYTE(IDE_HCYL_REG)<<16)
-					 |(IN_BYTE(IDE_LCYL_REG)<<8)
-					 | IN_BYTE(IDE_SECTOR_REG));
+				if ((drive->id->command_set_2 & 0x0400) &&
+				    (drive->id->cfs_enable_2 & 0x0400) &&
+				    (drive->addressing == 1)) {
+					__u64 sectors = 0;
+					u32 low = 0, high = 0;
+					low = read_24(drive);
+					OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG);
+					high = read_24(drive);
+
+					sectors = ((__u64)high << 24) | low;
+					printk(", LBAsect=%lld, high=%d, low=%d", sectors, high, low);
 				} else {
-					printk(", CHS=%d/%d/%d",
-					 (IN_BYTE(IDE_HCYL_REG)<<8) +
-					  IN_BYTE(IDE_LCYL_REG),
-					  cur & 0xf,
-					  IN_BYTE(IDE_SECTOR_REG));
+					byte cur = IN_BYTE(IDE_SELECT_REG);
+					if (cur & 0x40) {	/* using LBA? */
+						printk(", LBAsect=%ld", (unsigned long)
+						 ((cur&0xf)<<24)
+						 |(IN_BYTE(IDE_HCYL_REG)<<16)
+						 |(IN_BYTE(IDE_LCYL_REG)<<8)
+						 | IN_BYTE(IDE_SECTOR_REG));
+					} else {
+						printk(", CHS=%d/%d/%d",
+						 (IN_BYTE(IDE_HCYL_REG)<<8) +
+						  IN_BYTE(IDE_LCYL_REG),
+						  cur & 0xf,
+						  IN_BYTE(IDE_SECTOR_REG));
+					}
 				}
 				if (HWGROUP(drive) && HWGROUP(drive)->rq)
 					printk(", sector=%ld", HWGROUP(drive)->rq->sector);
@@ -986,7 +858,7 @@
 		u32 buffer[16];
 		unsigned int wcount = (i > 16) ? 16 : i;
 		i -= wcount;
-		ide_input_data (drive, buffer, wcount);
+		ata_input_data (drive, buffer, wcount);
 	}
 }
 
@@ -1004,9 +876,15 @@
 	/* retry only "normal" I/O: */
 	if (!(rq->flags & REQ_CMD)) {
 		rq->errors = 1;
+#if 0
+		if (rq->flags & REQ_DRIVE_TASKFILE)
+			ide_end_taskfile(drive, stat, err);
+		else
+#endif
 		ide_end_drive_cmd(drive, stat, err);
 		return ide_stopped;
 	}
+
 	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */
 		rq->errors |= ERROR_RESET;
 	} else {
@@ -1022,6 +900,7 @@
 			else if (err & TRK0_ERR)	/* help it find track zero */
 				rq->errors |= ERROR_RECAL;
 		}
+		/* pre bio (rq->cmd != WRITE) */
 		if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ)
 			try_to_flush_leftover_data(drive);
 	}
@@ -1073,7 +952,7 @@
 	if ((stat & DRQ_STAT) && args && args[3]) {
 		byte io_32bit = drive->io_32bit;
 		drive->io_32bit = 0;
-		ide_input_data(drive, &args[4], args[3] * SECTOR_WORDS);
+		ata_input_data(drive, &args[4], args[3] * SECTOR_WORDS);
 		drive->io_32bit = io_32bit;
 		while (((stat = GET_STAT()) & BUSY_STAT) && retries--)
 			udelay(100);
@@ -1168,14 +1047,63 @@
  */
 static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq)
 {
-	byte *args = rq->buffer;
-	if (args && (rq->flags & REQ_DRIVE_TASK)) {
+	if (rq->flags & REQ_DRIVE_TASKFILE) {
+		ide_task_t *args = rq->special;
+
+		if (!(args)) goto args_error;
+
+#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
+	{
+	printk(KERN_INFO "%s: ", drive->name);
+//	printk("TF.0=x%02x ", args->tfRegister[IDE_DATA_OFFSET]);
+	printk("TF.1=x%02x ", args->tfRegister[IDE_FEATURE_OFFSET]);
+	printk("TF.2=x%02x ", args->tfRegister[IDE_NSECTOR_OFFSET]);
+	printk("TF.3=x%02x ", args->tfRegister[IDE_SECTOR_OFFSET]);
+	printk("TF.4=x%02x ", args->tfRegister[IDE_LCYL_OFFSET]);
+	printk("TF.5=x%02x ", args->tfRegister[IDE_HCYL_OFFSET]);
+	printk("TF.6=x%02x ", args->tfRegister[IDE_SELECT_OFFSET]);
+	printk("TF.7=x%02x\n", args->tfRegister[IDE_COMMAND_OFFSET]);
+	printk(KERN_INFO "%s: ", drive->name);
+//	printk("HTF.0=x%02x ", args->hobRegister[IDE_DATA_OFFSET_HOB]);
+	printk("HTF.1=x%02x ", args->hobRegister[IDE_FEATURE_OFFSET_HOB]);
+	printk("HTF.2=x%02x ", args->hobRegister[IDE_NSECTOR_OFFSET_HOB]);
+	printk("HTF.3=x%02x ", args->hobRegister[IDE_SECTOR_OFFSET_HOB]);
+	printk("HTF.4=x%02x ", args->hobRegister[IDE_LCYL_OFFSET_HOB]);
+	printk("HTF.5=x%02x ", args->hobRegister[IDE_HCYL_OFFSET_HOB]);
+	printk("HTF.6=x%02x ", args->hobRegister[IDE_SELECT_OFFSET_HOB]);
+	printk("HTF.7=x%02x\n", args->hobRegister[IDE_CONTROL_OFFSET_HOB]);
+	}
+#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
+
+//		if (args->tf_out_flags.all == 0) {
+			do_taskfile(drive,
+				(struct hd_drive_task_hdr *)&args->tfRegister,
+				(struct hd_drive_hob_hdr *)&args->hobRegister,
+				args->handler);
+//		} else {
+//				return flagged_taskfile(drive, args);
+//		}
+
+		if (((args->command_type == IDE_DRIVE_TASK_RAW_WRITE) ||
+		     (args->command_type == IDE_DRIVE_TASK_OUT)) &&
+		      args->prehandler && args->handler)
+			return args->prehandler(drive, rq);
+		return ide_started;
+
+	} else if (rq->flags & REQ_DRIVE_TASK) {
+		byte *args = rq->buffer;
 		byte sel;
+
+		if (!(args)) goto args_error;
 #ifdef DEBUG
-		printk("%s: DRIVE_TASK_CMD data=x%02x cmd=0x%02x fr=0x%02x ns=0x%02x sc=0x%02x lcyl=0x%02x hcyl=0x%02x sel=0x%02x\n",
-			drive->name,
-			args[0], args[1], args[2], args[3],
-			args[4], args[5], args[6], args[7]);
+			printk("%s: DRIVE_TASK_CMD ", drive->name);
+			printk("cmd=0x%02x ", args[0]);
+			printk("fr=0x%02x ", args[1]);
+			printk("ns=0x%02x ", args[2]);
+			printk("sc=0x%02x ", args[3]);
+			printk("lcyl=0x%02x ", args[4]);
+			printk("hcyl=0x%02x ", args[5]);
+			printk("sel=0x%02x\n", args[6]);
 #endif
 		OUT_BYTE(args[1], IDE_FEATURE_REG);
 		OUT_BYTE(args[3], IDE_SECTOR_REG);
@@ -1187,10 +1115,16 @@
 		OUT_BYTE(sel, IDE_SELECT_REG);
 		ide_cmd(drive, args[0], args[2], &drive_cmd_intr);
 		return ide_started;
-	} else if (args) {
+	} else if (rq->flags & REQ_DRIVE_CMD) {
+
+		byte *args = rq->buffer;
+		if (!(args)) goto args_error;
 #ifdef DEBUG
-		printk("%s: DRIVE_CMD cmd=0x%02x sc=0x%02x fr=0x%02x xx=0x%02x\n",
-		 drive->name, args[0], args[1], args[2], args[3]);
+		printk("%s: DRIVE_CMD ", drive->name);
+		printk("cmd=0x%02x ", args[0]);
+		printk("sc=0x%02x ", args[1]);
+		printk("fr=0x%02x ", args[2]);
+		printk("xx=0x%02x\n", args[3]);
 #endif
 		if (args[0] == WIN_SMART) {
 			OUT_BYTE(0x4f, IDE_LCYL_REG);
@@ -1203,17 +1137,18 @@
 		OUT_BYTE(args[2],IDE_FEATURE_REG);
 		ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
 		return ide_started;
-	} else {
-		/*
-		 * NULL is actually a valid way of waiting for
-		 * all current requests to be flushed from the queue.
-		 */
+	}
+
+args_error:
+	/*
+	 * NULL is actually a valid way of waiting for
+	 * all current requests to be flushed from the queue.
+	 */
 #ifdef DEBUG
-		printk("%s: DRIVE_CMD (null)\n", drive->name);
+	printk("%s: DRIVE_CMD (null)\n", drive->name);
 #endif
-		ide_end_drive_cmd(drive, GET_STAT(), GET_ERR());
-		return ide_stopped;
-	}
+	ide_end_drive_cmd(drive, GET_STAT(), GET_ERR());
+	return ide_stopped;
 }
 
 /*
@@ -1264,7 +1199,7 @@
 		return startstop;
 	}
 	if (!drive->special.all) {
-		if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK))
+		if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK | REQ_DRIVE_TASKFILE))
 			return execute_drive_cmd(drive, rq);
 
 		if (drive->driver != NULL) {
@@ -1384,7 +1319,7 @@
  * will start the next request from the queue.  If no more work remains,
  * the driver will clear the hwgroup->flags IDE_BUSY flag and exit.
  */
-static void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq)
+static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
 {
 	ide_drive_t	*drive;
 	ide_hwif_t	*hwif;
@@ -1523,14 +1458,11 @@
 	HWGROUP(drive)->rq = NULL;
 
 	rq->errors = 0;
-	rq->sector = rq->bio->bi_sector;
-	rq->current_nr_sectors = bio_sectors(rq->bio);
-
-	/*
-	 * just to make sure...
-	 */
-	if (rq->bio)
+	if (rq->bio) {
+		rq->sector = rq->bio->bi_sector;
+		rq->current_nr_sectors = bio_iovec(rq->bio)->bv_len >> 9;
 		rq->buffer = NULL;
+	}
 }
 
 /*
@@ -1986,6 +1918,10 @@
 			(void) request_module("ide-tape");
 		if (drive->media == ide_floppy)
 			(void) request_module("ide-floppy");
+#if defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI)
+		if (drive->media == ide_scsi)
+			(void) request_module("ide-scsi");
+#endif /* defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI) */
 	}
 #endif /* CONFIG_KMOD */
 	while (drive->busy)
@@ -2609,6 +2545,61 @@
 	return((int) ((!system_bus_speed) ? ide_system_bus_speed() : system_bus_speed ));
 }
 
+int ide_reinit_drive (ide_drive_t *drive)
+{
+	switch (drive->media) {
+#ifdef CONFIG_BLK_DEV_IDECD
+		case ide_cdrom:
+		{
+			extern int ide_cdrom_reinit(ide_drive_t *drive);
+			if (ide_cdrom_reinit(drive))
+				return 1;
+			break;
+		}
+#endif /* CONFIG_BLK_DEV_IDECD */
+#ifdef CONFIG_BLK_DEV_IDEDISK
+		case ide_disk:
+		{
+			extern int idedisk_reinit(ide_drive_t *drive);
+			if (idedisk_reinit(drive))
+				return 1;
+			break;
+		}
+#endif /* CONFIG_BLK_DEV_IDEDISK */
+#ifdef CONFIG_BLK_DEV_IDEFLOPPY
+		case ide_floppy:
+		{
+			extern int idefloppy_reinit(ide_drive_t *drive);
+			if (idefloppy_reinit(drive))
+				return 1;
+			break;
+		}
+#endif /* CONFIG_BLK_DEV_IDEFLOPPY */
+#ifdef CONFIG_BLK_DEV_IDETAPE
+		case ide_tape:
+		{
+			extern int idetape_reinit(ide_drive_t *drive);
+			if (idetape_reinit(drive))
+				return 1;
+			break;
+		}
+#endif /* CONFIG_BLK_DEV_IDETAPE */
+#ifdef CONFIG_BLK_DEV_IDESCSI
+/*
+ *              {
+ *                      extern int idescsi_reinit(ide_drive_t *drive);
+ *                      if (idescsi_reinit(drive))
+ *                              return 1;
+ *                      break;
+ * }
+ */
+#endif /* CONFIG_BLK_DEV_IDESCSI */
+		default:
+			return 1;
+	}
+	return 0;
+}
+
 static int ide_ioctl (struct inode *inode, struct file *file,
 			unsigned int cmd, unsigned long arg)
 {
@@ -2695,57 +2686,35 @@
 					drive->nice1		<<	IDE_NICE_1		|
 					drive->nice2		<<	IDE_NICE_2,
 					(long *) arg);
+
+#ifdef CONFIG_IDE_TASK_IOCTL
+		case HDIO_DRIVE_TASKFILE:
+		        if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+				return -EACCES;
+			switch(drive->media) {
+				case ide_disk:
+					return ide_taskfile_ioctl(drive, inode, file, cmd, arg);
+#ifdef CONFIG_PKT_TASK_IOCTL
+				case ide_cdrom:
+				case ide_tape:
+				case ide_floppy:
+					return pkt_taskfile_ioctl(drive, inode, file, cmd, arg);
+#endif /* CONFIG_PKT_TASK_IOCTL */
+				default:
+					return -ENOMSG;
+			}
+#endif /* CONFIG_IDE_TASK_IOCTL */
+
 		case HDIO_DRIVE_CMD:
-		{
-			byte args[4], *argbuf = args;
-			byte xfer_rate = 0;
-			int argsize = 4;
-			if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES;
-			if (NULL == (void *) arg)
-				return ide_do_drive_cmd(drive, &rq, ide_wait);
-			if (copy_from_user(args, (void *)arg, 4))
-				return -EFAULT;
-			if (args[3]) {
-				argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
-				argbuf = kmalloc(argsize, GFP_KERNEL);
-				if (argbuf == NULL)
-					return -ENOMEM;
-				memcpy(argbuf, args, 4);
-			}
-
-			if (set_transfer(drive, args[0], args[1], args[2])) {
-				xfer_rate = args[1];
-				if (ide_ata66_check(drive, args[0], args[1], args[2]))
-					goto abort;
-			}
-
-			err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
-
-			if (!err && xfer_rate) {
-				/* active-retuning-calls future */
-				if ((HWIF(drive)->speedproc) != NULL)
-					HWIF(drive)->speedproc(drive, xfer_rate);
-				ide_driveid_update(drive);
-			}
-		abort:
-			if (copy_to_user((void *)arg, argbuf, argsize))
-				err = -EFAULT;
-			if (argsize > 4)
-				kfree(argbuf);
-			return err;
-		}
+			if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+				return -EACCES;
+			return ide_cmd_ioctl(drive, inode, file, cmd, arg);
+
 		case HDIO_DRIVE_TASK:
-		{
-			byte args[7], *argbuf = args;
-			int argsize = 7;
-			if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES;
-			if (copy_from_user(args, (void *)arg, 7))
-				return -EFAULT;
-			err = ide_wait_cmd_task(drive, argbuf);
-			if (copy_to_user((void *)arg, argbuf, argsize))
-				err = -EFAULT;
-			return err;
-		}
+			if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+				return -EACCES;
+			return ide_task_ioctl(drive, inode, file, cmd, arg);
+
 		case HDIO_SCAN_HWIF:
 		{
 			int args[3];
@@ -2775,7 +2744,24 @@
 			drive->nice1 = (arg >> IDE_NICE_1) & 1;
 			return 0;
 		case HDIO_DRIVE_RESET:
+		{
+			unsigned long flags;
+			ide_hwgroup_t *hwgroup = HWGROUP(drive);
+
 			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+#if 1
+			spin_lock_irqsave(&ide_lock, flags);
+			if (hwgroup->handler != NULL) {
+				printk("%s: ide_set_handler: handler not null; %p\n", drive->name, hwgroup->handler);
+				(void) hwgroup->handler(drive);
+//				hwgroup->handler = NULL;
+//				hwgroup->expiry	= NULL;
+				hwgroup->timer.expires = jiffies + 0;;
+				del_timer(&hwgroup->timer);
+			}
+			spin_unlock_irqrestore(&ide_lock, flags);
+
+#endif
 			(void) ide_do_reset(drive);
 			if (drive->suspend_reset) {
 /*
@@ -2790,7 +2776,7 @@
 				return ide_revalidate_disk(inode->i_rdev);
 			}
 			return 0;
-
+		}
 		case BLKGETSIZE:
 		case BLKGETSIZE64:
 		case BLKROSET:
@@ -2822,7 +2808,7 @@
 			if (!capable(CAP_SYS_ADMIN))
 				return -EACCES;
 			if (HWIF(drive)->busproc)
-				HWIF(drive)->busproc(HWIF(drive), arg);
+				HWIF(drive)->busproc(drive, (int)arg);
 			return 0;
 
 		default:
@@ -3483,6 +3469,16 @@
 	return ide_unregister_subdriver(drive);
 }
 
+static int default_standby (ide_drive_t *drive)
+{
+	return 0;
+}
+
+static int default_flushcache (ide_drive_t *drive)
+{
+	return 0;
+}
+
 static ide_startstop_t default_do_request(ide_drive_t *drive, struct request *rq, unsigned long block)
 {
 	ide_end_request(0, HWGROUP(drive));
@@ -3545,6 +3541,8 @@
 	ide_driver_t *d = drive->driver;
 
 	if (d->cleanup == NULL)		d->cleanup = default_cleanup;
+	if (d->standby == NULL)		d->standby = default_standby;
+	if (d->flushcache == NULL)	d->flushcache = default_flushcache;
 	if (d->do_request == NULL)	d->do_request = default_do_request;
 	if (d->end_request == NULL)	d->end_request = default_end_request;
 	if (d->ioctl == NULL)		d->ioctl = default_ioctl;
@@ -3696,10 +3694,6 @@
 EXPORT_SYMBOL(ide_register_subdriver);
 EXPORT_SYMBOL(ide_unregister_subdriver);
 EXPORT_SYMBOL(ide_replace_subdriver);
-EXPORT_SYMBOL(ide_input_data);
-EXPORT_SYMBOL(ide_output_data);
-EXPORT_SYMBOL(atapi_input_bytes);
-EXPORT_SYMBOL(atapi_output_bytes);
 EXPORT_SYMBOL(ide_set_handler);
 EXPORT_SYMBOL(ide_dump_status);
 EXPORT_SYMBOL(ide_error);
@@ -3724,6 +3718,8 @@
 EXPORT_SYMBOL(ide_remove_proc_entries);
 EXPORT_SYMBOL(proc_ide_read_geometry);
 EXPORT_SYMBOL(create_proc_ide_interfaces);
+EXPORT_SYMBOL(recreate_proc_ide_device);
+EXPORT_SYMBOL(destroy_proc_ide_device);
 #endif
 EXPORT_SYMBOL(ide_add_setting);
 EXPORT_SYMBOL(ide_remove_setting);
@@ -3738,6 +3734,54 @@
 
 EXPORT_SYMBOL(system_bus_clock);
 
+EXPORT_SYMBOL(ide_reinit_drive);
+
+static int ide_notify_reboot (struct notifier_block *this, unsigned long event, void *x)
+{
+	ide_hwif_t *hwif;
+	ide_drive_t *drive;
+	int i, unit;
+
+	switch (event) {
+		case SYS_HALT:
+		case SYS_POWER_OFF:
+		case SYS_RESTART:
+			break;
+		default:
+			return NOTIFY_DONE;
+	}
+
+	printk("flushing ide devices: ");
+
+	for (i = 0; i < MAX_HWIFS; i++) {
+		hwif = &ide_hwifs[i];
+		if (!hwif->present)
+			continue;
+		for (unit = 0; unit < MAX_DRIVES; ++unit) {
+			drive = &hwif->drives[unit];
+			if (!drive->present)
+				continue;
+
+			/* set the drive to standby */
+			printk("%s ", drive->name);
+			if (event != SYS_RESTART)
+				if (drive->driver != NULL && DRIVER(drive)->standby(drive))
+				continue;
+
+			if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
+				continue;
+		}
+	}
+	printk("\n");
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block ide_notifier = {
+	ide_notify_reboot,
+	NULL,
+	5
+};
+
 /*
  * This is gets invoked once during initialization, to set *everything* up
  */
@@ -3765,6 +3809,7 @@
 			ide_geninit(hwif);
 	}
 
+	register_reboot_notifier(&ide_notifier);
 	return 0;
 }
 
@@ -3797,6 +3842,7 @@
 {
 	int index;
 
+	unregister_reboot_notifier(&ide_notifier);
 	for (index = 0; index < MAX_HWIFS; ++index) {
 		ide_unregister(index);
 #if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/pdc202xx.c linux/drivers/ide/pdc202xx.c
--- v2.5.2/linux/drivers/ide/pdc202xx.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/pdc202xx.c	Tue Jan 15 11:27:30 2002
@@ -108,7 +108,7 @@
 	u32 bibma  = pci_resource_start(dev, 4);
 	u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0;
 	u16 reg50h = 0, pmask = (1<<10), smask = (1<<11);
-	u8 hi = 0, lo = 0, invalid_data_set = 0;
+	u8 hi = 0, lo = 0;
 
         /*
          * at that point bibma+0x2 et bibma+0xa are byte registers
@@ -132,11 +132,6 @@
 	pci_read_config_dword(dev, 0x6c, &reg6ch);
 
 	switch(dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20268:
-		case PCI_DEVICE_ID_PROMISE_20268R:
-			p += sprintf(p, "\n                                PDC20268 TX2 Chipset.\n");
-			invalid_data_set = 1;
-			break;
 		case PCI_DEVICE_ID_PROMISE_20267:
 			p += sprintf(p, "\n                                PDC20267 Chipset.\n");
 			break;
@@ -180,45 +175,77 @@
 	p += sprintf(p, "           Mode %s                      Mode %s\n",
 		(sc1a & 0x01) ? "MASTER" : "PCI   ",
 		(sc1b & 0x01) ? "MASTER" : "PCI   ");
-	if (!(invalid_data_set))
-		p += sprintf(p, "                %s                     %s\n",
-			(sc1d & 0x08) ? "Error       " :
-			((sc1d & 0x05) == 0x05) ? "Not My INTR " :
-			(sc1d & 0x04) ? "Interrupting" :
-			(sc1d & 0x02) ? "FIFO Full   " :
-			(sc1d & 0x01) ? "FIFO Empty  " : "????????????",
-			(sc1d & 0x80) ? "Error       " :
-			((sc1d & 0x50) == 0x50) ? "Not My INTR " :
-			(sc1d & 0x40) ? "Interrupting" :
-			(sc1d & 0x20) ? "FIFO Full   " :
-			(sc1d & 0x10) ? "FIFO Empty  " : "????????????");
+	p += sprintf(p, "                %s                     %s\n",
+		(sc1d & 0x08) ? "Error       " :
+		((sc1d & 0x05) == 0x05) ? "Not My INTR " :
+		(sc1d & 0x04) ? "Interrupting" :
+		(sc1d & 0x02) ? "FIFO Full   " :
+		(sc1d & 0x01) ? "FIFO Empty  " : "????????????",
+		(sc1d & 0x80) ? "Error       " :
+		((sc1d & 0x50) == 0x50) ? "Not My INTR " :
+		(sc1d & 0x40) ? "Interrupting" :
+		(sc1d & 0x20) ? "FIFO Full   " :
+		(sc1d & 0x10) ? "FIFO Empty  " : "????????????");
 	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
 	p += sprintf(p, "DMA enabled:    %s              %s             %s               %s\n",
 		(c0&0x20)?"yes":"no ",(c0&0x40)?"yes":"no ",(c1&0x20)?"yes":"no ",(c1&0x40)?"yes":"no ");
-	if (!(invalid_data_set))
-		p += sprintf(p, "DMA Mode:       %s           %s          %s            %s\n",
-			pdc202xx_ultra_verbose(reg60h, (reg50h & pmask)),
-			pdc202xx_ultra_verbose(reg64h, (reg50h & pmask)),
-			pdc202xx_ultra_verbose(reg68h, (reg50h & smask)),
-			pdc202xx_ultra_verbose(reg6ch, (reg50h & smask)));
-	if (!(invalid_data_set))
-		p += sprintf(p, "PIO Mode:       %s            %s           %s            %s\n",
-			pdc202xx_pio_verbose(reg60h),
-			pdc202xx_pio_verbose(reg64h),
-			pdc202xx_pio_verbose(reg68h),
-			pdc202xx_pio_verbose(reg6ch));
+	p += sprintf(p, "DMA Mode:       %s           %s          %s            %s\n",
+		pdc202xx_ultra_verbose(reg60h, (reg50h & pmask)),
+		pdc202xx_ultra_verbose(reg64h, (reg50h & pmask)),
+		pdc202xx_ultra_verbose(reg68h, (reg50h & smask)),
+		pdc202xx_ultra_verbose(reg6ch, (reg50h & smask)));
+	p += sprintf(p, "PIO Mode:       %s            %s           %s            %s\n",
+		pdc202xx_pio_verbose(reg60h),
+		pdc202xx_pio_verbose(reg64h),
+		pdc202xx_pio_verbose(reg68h),
+		pdc202xx_pio_verbose(reg6ch));
 #if 0
 	p += sprintf(p, "--------------- Can ATAPI DMA ---------------\n");
 #endif
-	if (invalid_data_set)
-		p += sprintf(p, "--------------- Cannot Decode HOST ---------------\n");
+	return (char *)p;
+}
+
+static char * pdc202xx_info_new (char *buf, struct pci_dev *dev)
+{
+	char *p = buf;
+//	u32 bibma = pci_resource_start(dev, 4);
+
+//	u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0;
+//	u16 reg50h = 0, word88 = 0;
+//	int udmasel[4]={0,0,0,0}, piosel[4]={0,0,0,0}, i=0, hd=0;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20275:
+			p += sprintf(p, "\n                                PDC20275 Chipset.\n");
+			break;
+		case PCI_DEVICE_ID_PROMISE_20269:
+			p += sprintf(p, "\n                                PDC20269 TX2 Chipset.\n");
+			break;
+		case PCI_DEVICE_ID_PROMISE_20268:
+		case PCI_DEVICE_ID_PROMISE_20268R:
+			p += sprintf(p, "\n                                PDC20268 TX2 Chipset.\n");
+			break;
+default:
+			p += sprintf(p, "\n                                PDC202XX Chipset.\n");
+			break;
+	}
 	return (char *)p;
 }
 
 static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count)
 {
 	char *p = buffer;
-	p = pdc202xx_info(buffer, bmide_dev);
+	switch(bmide_dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20269:
+		case PCI_DEVICE_ID_PROMISE_20268:
+		case PCI_DEVICE_ID_PROMISE_20268R:
+			p = pdc202xx_info_new(buffer, bmide_dev);
+			break;
+		default:
+			p = pdc202xx_info(buffer, bmide_dev);
+			break;
+	}
 	return p-buffer;	/* => must be less than 4k! */
 }
 #endif  /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */
@@ -387,9 +414,6 @@
 
 	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))	return -1;
 
-	if (dev->device == PCI_DEVICE_ID_PROMISE_20268)
-		goto skip_register_hell;
-
 	pci_read_config_dword(dev, drive_pci, &drive_conf);
 	pci_read_config_byte(dev, (drive_pci), &AP);
 	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
@@ -432,6 +456,7 @@
 
 	switch(speed) {
 #ifdef CONFIG_BLK_DEV_IDEDMA
+		/* case XFER_UDMA_6: */
 		case XFER_UDMA_5:
 		case XFER_UDMA_4:	TB = 0x20; TC = 0x01; break;	/* speed 8 == UDMA mode 4 */
 		case XFER_UDMA_3:	TB = 0x40; TC = 0x02; break;	/* speed 7 == UDMA mode 3 */
@@ -477,8 +502,6 @@
 	decode_registers(REG_D, DP);
 #endif /* PDC202XX_DECODE_REGISTER_INFO */
 
-skip_register_hell:
-
 	if (!drive->init_speed)
 		drive->init_speed = speed;
 	err = ide_config_drive_speed(drive, speed);
@@ -494,6 +517,159 @@
 	return err;
 }
 
+static int pdc202xx_new_tune_chipset (ide_drive_t *drive, byte speed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	unsigned long indexreg	= (hwif->dma_base + 1);
+	unsigned long datareg	= (hwif->dma_base + 3);
+#else
+	struct pci_dev *dev	= hwif->pci_dev;
+	unsigned long high_16	= pci_resource_start(dev, 4);
+	unsigned long indexreg	= high_16 + (hwif->channel ? 0x09 : 0x01);
+	unsigned long datareg	= (indexreg + 2);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	byte thold		= 0x10;
+	byte adj		= (drive->dn%2) ? 0x08 : 0x00;
+
+	int                     err;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (speed == XFER_UDMA_2) {
+		OUT_BYTE((thold + adj), indexreg);
+		OUT_BYTE((IN_BYTE(datareg) & 0x7f), datareg);
+	}
+	switch (speed) {
+		case XFER_UDMA_7:
+			speed = XFER_UDMA_6;
+		case XFER_UDMA_6:
+			OUT_BYTE((0x10 + adj), indexreg);
+			OUT_BYTE(0x1a, datareg);
+			OUT_BYTE((0x11 + adj), indexreg);
+			OUT_BYTE(0x01, datareg);
+			OUT_BYTE((0x12 + adj), indexreg);
+			OUT_BYTE(0xcb, datareg);
+			break;
+		case XFER_UDMA_5:
+			OUT_BYTE((0x10 + adj), indexreg);
+			OUT_BYTE(0x1a, datareg);
+			OUT_BYTE((0x11 + adj), indexreg);
+			OUT_BYTE(0x02, datareg);
+			OUT_BYTE((0x12 + adj), indexreg);
+			OUT_BYTE(0xcb, datareg);
+			break;
+		case XFER_UDMA_4:
+			OUT_BYTE((0x10 + adj), indexreg);
+			OUT_BYTE(0x1a, datareg);
+			OUT_BYTE((0x11 + adj), indexreg);
+			OUT_BYTE(0x03, datareg);
+			OUT_BYTE((0x12 + adj), indexreg);
+			OUT_BYTE(0xcd, datareg);
+			break;
+		case XFER_UDMA_3:
+			OUT_BYTE((0x10 + adj), indexreg);
+			OUT_BYTE(0x1a, datareg);
+			OUT_BYTE((0x11 + adj), indexreg);
+			OUT_BYTE(0x05, datareg);
+			OUT_BYTE((0x12 + adj), indexreg);
+			OUT_BYTE(0xcd, datareg);
+			break;
+		case XFER_UDMA_2:
+			OUT_BYTE((0x10 + adj), indexreg);
+			OUT_BYTE(0x2a, datareg);
+			OUT_BYTE((0x11 + adj), indexreg);
+			OUT_BYTE(0x07, datareg);
+			OUT_BYTE((0x12 + adj), indexreg);
+			OUT_BYTE(0xcd, datareg);
+			break;
+		case XFER_UDMA_1:
+			OUT_BYTE((0x10 + adj), indexreg);
+			OUT_BYTE(0x3a, datareg);
+			OUT_BYTE((0x11 + adj), indexreg);
+			OUT_BYTE(0x0a, datareg);
+			OUT_BYTE((0x12 + adj), indexreg);
+			OUT_BYTE(0xd0, datareg);
+			break;
+		case XFER_UDMA_0:
+			OUT_BYTE((0x10 + adj), indexreg);
+			OUT_BYTE(0x4a, datareg);
+			OUT_BYTE((0x11 + adj), indexreg);
+			OUT_BYTE(0x0f, datareg);
+			OUT_BYTE((0x12 + adj), indexreg);
+			OUT_BYTE(0xd5, datareg);
+			break;
+		case XFER_MW_DMA_2:
+			OUT_BYTE((0x0e + adj), indexreg);
+			OUT_BYTE(0x69, datareg);
+			OUT_BYTE((0x0f + adj), indexreg);
+			OUT_BYTE(0x25, datareg);
+			break;
+		case XFER_MW_DMA_1:
+			OUT_BYTE((0x0e + adj), indexreg);
+			OUT_BYTE(0x6b, datareg);
+			OUT_BYTE((0x0f+ adj), indexreg);
+			OUT_BYTE(0x27, datareg);
+			break;
+		case XFER_MW_DMA_0:
+			OUT_BYTE((0x0e + adj), indexreg);
+			OUT_BYTE(0xdf, datareg);
+			OUT_BYTE((0x0f + adj), indexreg);
+			OUT_BYTE(0x5f, datareg);
+			break;
+#else
+	switch (speed) {
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+		case XFER_PIO_4:
+			OUT_BYTE((0x0c + adj), indexreg);
+			OUT_BYTE(0x23, datareg);
+			OUT_BYTE((0x0d + adj), indexreg);
+			OUT_BYTE(0x09, datareg);
+			OUT_BYTE((0x13 + adj), indexreg);
+			OUT_BYTE(0x25, datareg);
+			break;
+		case XFER_PIO_3:
+			OUT_BYTE((0x0c + adj), indexreg);
+			OUT_BYTE(0x27, datareg);
+			OUT_BYTE((0x0d + adj), indexreg);
+			OUT_BYTE(0x0d, datareg);
+			OUT_BYTE((0x13 + adj), indexreg);
+			OUT_BYTE(0x35, datareg);
+			break;
+		case XFER_PIO_2:
+			OUT_BYTE((0x0c + adj), indexreg);
+			OUT_BYTE(0x23, datareg);
+			OUT_BYTE((0x0d + adj), indexreg);
+			OUT_BYTE(0x26, datareg);
+			OUT_BYTE((0x13 + adj), indexreg);
+			OUT_BYTE(0x64, datareg);
+			break;
+		case XFER_PIO_1:
+			OUT_BYTE((0x0c + adj), indexreg);
+			OUT_BYTE(0x46, datareg);
+			OUT_BYTE((0x0d + adj), indexreg);
+			OUT_BYTE(0x29, datareg);
+			OUT_BYTE((0x13 + adj), indexreg);
+			OUT_BYTE(0xa4, datareg);
+			break;
+		case XFER_PIO_0:
+			OUT_BYTE((0x0c + adj), indexreg);
+			OUT_BYTE(0xfb, datareg);
+			OUT_BYTE((0x0d + adj), indexreg);
+			OUT_BYTE(0x2b, datareg);
+			OUT_BYTE((0x13 + adj), indexreg);
+			OUT_BYTE(0xac, datareg);
+			break;
+		default:
+	}
+
+	if (!drive->init_speed)
+		drive->init_speed = speed;
+	err = ide_config_drive_speed(drive, speed);
+	drive->current_speed = speed;
+
+	return err;
+}
+
 /*   0    1    2    3    4    5    6   7   8
  * 960, 480, 390, 300, 240, 180, 120, 90, 60
  *           180, 150, 120,  90,  60
@@ -524,18 +700,75 @@
 	struct pci_dev *dev	= hwif->pci_dev;
 	unsigned long high_16   = pci_resource_start(dev, 4);
 	unsigned long dma_base  = hwif->dma_base;
+	unsigned long indexreg	= dma_base + 1;
+	unsigned long datareg	= dma_base + 3;
+	byte iordy		= 0x13;
+	byte adj		= (drive->dn%2) ? 0x08 : 0x00;
+	byte cable		= 0;
+	byte jumpbit		= 0;
 	byte unit		= (drive->select.b.unit & 0x01);
-
 	unsigned int		drive_conf;
-	byte			drive_pci;
+	byte			drive_pci = 0;
 	byte			test1, test2, speed = -1;
 	byte			AP;
 	unsigned short		EP;
-	byte CLKSPD		= IN_BYTE(high_16 + 0x11);
-	byte udma_33		= ultra ? (inb(high_16 + 0x001f) & 1) : 0;
+	byte CLKSPD		= 0;
+	byte udma_33		= ultra;
+//	byte udma_33		= ultra ? (IN_BYTE(high_16 + 0x001f) & 1) : 0;
 	byte udma_66		= ((eighty_ninty_three(drive)) && udma_33) ? 1 : 0;
-	byte udma_100		= (((dev->device == PCI_DEVICE_ID_PROMISE_20265) || (dev->device == PCI_DEVICE_ID_PROMISE_20267) || (dev->device == PCI_DEVICE_ID_PROMISE_20268)) && udma_66) ? 1 : 0;
+	byte udma_100		= 0;
+	byte udma_133		= 0;
+	byte mask		= hwif->channel ? 0x08 : 0x02;
+	unsigned short c_mask	= hwif->channel ? (1<<11) : (1<<10);
+
+	byte ultra_66		= ((id->dma_ultra & 0x0010) ||
+				   (id->dma_ultra & 0x0008)) ? 1 : 0;
+	byte ultra_100		= ((id->dma_ultra & 0x0020) ||
+				   (ultra_66)) ? 1 : 0;
+	byte ultra_133		= ((id->dma_ultra & 0x0040) ||
+				   (ultra_100)) ? 1 : 0;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20269:
+			udma_133 = (udma_66) ? 1 : 0;
+			udma_100 = (udma_66) ? 1 : 0;
+			OUT_BYTE(0x0b, (hwif->dma_base + 1));
+			cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04));
+			jumpbit = 1;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20268R:
+			udma_100 = 1;
+			udma_66 = 1;
+			OUT_BYTE(0x0b, (hwif->dma_base + 1));
+			cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04));
+			jumpbit = 1;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20268:
+			udma_100 = (udma_66) ? 1 : 0;
+			OUT_BYTE(0x0b, (hwif->dma_base + 1));
+			cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04));
+			jumpbit = 1;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20267:
+		case PCI_DEVICE_ID_PROMISE_20265:
+			udma_100 = (udma_66) ? 1 : 0;
+			pci_read_config_word(dev, 0x50, &EP);
+			cable = (EP & c_mask);
+			jumpbit = 0;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20262:
+			pci_read_config_word(dev, 0x50, &EP);
+			cable = (EP & c_mask);
+			jumpbit = 0;
+			break;
+		default:
+			udma_100 = 0; udma_133 = 0; cable = 1; jumpbit = 0;
+			break;
+	}
 
+	if (!jumpbit)
+		CLKSPD = IN_BYTE(high_16 + 0x11);
 	/*
 	 * Set the control register to use the 66Mhz system
 	 * clock for UDMA 3/4 mode operation. If one drive on
@@ -549,47 +782,52 @@
 	 * parameters.
 	 */
 
-	byte mask		= hwif->channel ? 0x08 : 0x02;
-	unsigned short c_mask	= hwif->channel ? (1<<11) : (1<<10);
-	byte ultra_66		= ((id->dma_ultra & 0x0010) ||
-				   (id->dma_ultra & 0x0008)) ? 1 : 0;
-	byte ultra_100		= ((id->dma_ultra & 0x0020) ||
-				   (id->dma_ultra & 0x0010) ||
-				   (id->dma_ultra & 0x0008)) ? 1 : 0;
-
-	if (dev->device == PCI_DEVICE_ID_PROMISE_20268)
-		goto jump_pci_mucking;
-
-	pci_read_config_word(dev, 0x50, &EP);
-
-	if (((ultra_66) || (ultra_100)) && (EP & c_mask)) {
+	if (((ultra_66) || (ultra_100) || (ultra_133)) && (cable)) {
 #ifdef DEBUG
 		printk("ULTRA66: %s channel of Ultra 66 requires an 80-pin cable for Ultra66 operation.\n", hwif->channel ? "Secondary" : "Primary");
 		printk("         Switching to Ultra33 mode.\n");
 #endif /* DEBUG */
 		/* Primary   : zero out second bit */
 		/* Secondary : zero out fourth bit */
-		OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
+		if (!jumpbit)
+			OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
+		printk("Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary");
+		printk("%s reduced to Ultra33 mode.\n", drive->name);
+		udma_66 = 0; udma_100 = 0; udma_133 = 0;
 	} else {
-		if ((ultra_66) || (ultra_100)) {
+		if ((ultra_66) || (ultra_100) || (ultra_133)) {
 			/*
 			 * check to make sure drive on same channel
 			 * is u66 capable
 			 */
 			if (hwif->drives[!(drive->dn%2)].id) {
-				if ((hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0020) ||
+				if ((hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0040) ||
+				    (hwif->drives[!(drive->dn%2)].id->dma_ultra
+& 0x0020) ||
 				    (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0010) ||
 				    (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0008)) {
-					OUT_BYTE(CLKSPD | mask, (high_16 + 0x11));
+					if (!jumpbit)
+						OUT_BYTE(CLKSPD | mask, (high_16 + 0x11));
 				} else {
-					OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
+					if (!jumpbit)
+						OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
 				}
 			} else { /* udma4 drive by itself */
-				OUT_BYTE(CLKSPD | mask, (high_16 + 0x11));
+				if (!jumpbit)
+					OUT_BYTE(CLKSPD | mask, (high_16 + 0x11));
 			}
 		}
 	}
 
+	if (jumpbit) {
+		if (drive->media != ide_disk)	return ide_dma_off_quietly;
+		if (id->capability & 4) {	/* IORDY_EN & PREFETCH_EN */
+			OUT_BYTE((iordy + adj), indexreg);
+			OUT_BYTE((IN_BYTE(datareg)|0x03), datareg);
+		}
+		goto jumpbit_is_set;
+	}
+
 	switch(drive->dn) {
 		case 0:	drive_pci = 0x60;
 			pci_read_config_dword(dev, drive_pci, &drive_conf);
@@ -640,31 +878,33 @@
 	if (drive->media == ide_disk)	/* PREFETCH_EN */
 		pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN);
 
-jump_pci_mucking:
+jumpbit_is_set:
 
-	if ((id->dma_ultra & 0x0020) && (udma_100))	speed = XFER_UDMA_5;
-	else if ((id->dma_ultra & 0x0010) && (udma_66))	speed = XFER_UDMA_4;
-	else if ((id->dma_ultra & 0x0008) && (udma_66))	speed = XFER_UDMA_3;
-	else if ((id->dma_ultra & 0x0004) && (udma_33))	speed = XFER_UDMA_2;
-	else if ((id->dma_ultra & 0x0002) && (udma_33))	speed = XFER_UDMA_1;
-	else if ((id->dma_ultra & 0x0001) && (udma_33))	speed = XFER_UDMA_0;
+	if ((id->dma_ultra & 0x0040)&&(udma_133))	speed = XFER_UDMA_6;
+	else if ((id->dma_ultra & 0x0020)&&(udma_100))	speed = XFER_UDMA_5;
+	else if ((id->dma_ultra & 0x0010)&&(udma_66))	speed = XFER_UDMA_4;
+	else if ((id->dma_ultra & 0x0008)&&(udma_66))	speed = XFER_UDMA_3;
+	else if ((id->dma_ultra & 0x0004)&&(udma_33))	speed = XFER_UDMA_2;
+	else if ((id->dma_ultra & 0x0002)&&(udma_33))	speed = XFER_UDMA_1;
+	else if ((id->dma_ultra & 0x0001)&&(udma_33))	speed = XFER_UDMA_0;
 	else if (id->dma_mword & 0x0004)		speed = XFER_MW_DMA_2;
 	else if (id->dma_mword & 0x0002)		speed = XFER_MW_DMA_1;
 	else if (id->dma_mword & 0x0001)		speed = XFER_MW_DMA_0;
-	else if (id->dma_1word & 0x0004)		speed = XFER_SW_DMA_2;
-	else if (id->dma_1word & 0x0002)		speed = XFER_SW_DMA_1;
-	else if (id->dma_1word & 0x0001)		speed = XFER_SW_DMA_0;
+	else if ((id->dma_1word & 0x0004)&&(!jumpbit))	speed = XFER_SW_DMA_2;
+	else if ((id->dma_1word & 0x0002)&&(!jumpbit))	speed = XFER_SW_DMA_1;
+	else if ((id->dma_1word & 0x0001)&&(!jumpbit))	speed = XFER_SW_DMA_0;
 	else {
 		/* restore original pci-config space */
-		if (dev->device != PCI_DEVICE_ID_PROMISE_20268)
+		if (!jumpbit)
 			pci_write_config_dword(dev, drive_pci, drive_conf);
 		return ide_dma_off_quietly;
 	}
 
 	outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
-	(void) pdc202xx_tune_chipset(drive, speed);
+	(void) hwif->speedproc(drive, speed);
 
-	return ((int)	((id->dma_ultra >> 11) & 7) ? ide_dma_on :
+	return ((int)	((id->dma_ultra >> 14) & 3) ? ide_dma_on :
+			((id->dma_ultra >> 11) & 7) ? ide_dma_on :
 			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
 			((id->dma_mword >> 8) & 7) ? ide_dma_on : 
 			((id->dma_1word >> 8) & 7) ? ide_dma_on :
@@ -685,7 +925,7 @@
 		}
 		dma_func = ide_dma_off_quietly;
 		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x002F) {
+			if (id->dma_ultra & 0x007F) {
 				/* Force if Capable UltraDMA */
 				dma_func = config_chipset_for_dma(drive, 1);
 				if ((id->field_valid & 2) &&
@@ -732,16 +972,65 @@
  */
 int pdc202xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
-	byte dma_stat = 0, sc1d = 0;
-	unsigned long high_16	= pci_resource_start(HWIF(drive)->pci_dev, 4);
-	unsigned long dma_base	= HWIF(drive)->dma_base;
+	byte dma_stat		= 0;
+	byte sc1d		= 0;
+	byte newchip		= 0;
+	byte clock		= 0;
+	byte hardware48hack	= 0;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	unsigned long high_16	= pci_resource_start(dev, 4);
+	unsigned long atapi_reg	= high_16 + (hwif->channel ? 0x24 : 0x00);
+	unsigned long dma_base	= hwif->dma_base;
+
+	switch (dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20269:
+		case PCI_DEVICE_ID_PROMISE_20268R:
+		case PCI_DEVICE_ID_PROMISE_20268:
+			newchip = 1;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20267:
+		case PCI_DEVICE_ID_PROMISE_20265:
+		case PCI_DEVICE_ID_PROMISE_20262:
+			hardware48hack = 1;
+			clock = IN_BYTE(high_16 + 0x11);
+		default:
+			break;
+	}
 
 	switch (func) {
 		case ide_dma_check:
 			return config_drive_xfer_rate(drive);
+		case ide_dma_begin:
+			/* Note that this is done *after* the cmd has
+			 * been issued to the drive, as per the BM-IDE spec.
+			 * The Promise Ultra33 doesn't work correctly when
+			 * we do this part before issuing the drive cmd.
+			 */
+			if ((drive->addressing) && (hardware48hack)) {
+				struct request *rq = HWGROUP(drive)->rq;
+				unsigned long word_count = 0;
+
+				outb(clock|(hwif->channel ? 0x08 : 0x02), high_16 + 0x11);
+				word_count = (rq->nr_sectors << 8);
+				word_count = (rq_data_dir(rq) == READ) ? word_count | 0x05000000 : word_count | 0x06000000;
+				outl(word_count, atapi_reg);
+			}
+			break;
+		case ide_dma_end:
+			if ((drive->addressing) && (hardware48hack)) {
+				outl(0, atapi_reg);	/* zero out extra */
+				clock = IN_BYTE(high_16 + 0x11);
+				OUT_BYTE(clock & ~(hwif->channel ? 0x08:0x02), high_16 + 0x11);
+			}
+			break;
 		case ide_dma_test_irq:	/* returns 1 if dma irq issued, 0 otherwise */
-			dma_stat = inb(dma_base+2);
-			sc1d = inb(high_16 + 0x001d);
+			dma_stat = IN_BYTE(dma_base+2);
+			if (newchip)
+				return (dma_stat & 4) == 4;
+
+			sc1d = IN_BYTE(high_16 + 0x001d);
 			if (HWIF(drive)->channel) {
 				if ((sc1d & 0x50) == 0x50) goto somebody_else;
 				else if ((sc1d & 0x40) == 0x40)
@@ -764,61 +1053,113 @@
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
+void pdc202xx_new_reset (ide_drive_t *drive)
+{
+	OUT_BYTE(0x04,IDE_CONTROL_REG);
+	mdelay(1000);
+	OUT_BYTE(0x00,IDE_CONTROL_REG);
+	mdelay(1000);
+	printk("PDC202XX: %s channel reset.\n",
+		HWIF(drive)->channel ? "Secondary" : "Primary");
+}
+
 void pdc202xx_reset (ide_drive_t *drive)
 {
 	unsigned long high_16	= pci_resource_start(HWIF(drive)->pci_dev, 4);
-	byte udma_speed_flag	= inb(high_16 + 0x001f);
+	byte udma_speed_flag	= IN_BYTE(high_16 + 0x001f);
 
 	OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
 	mdelay(100);
 	OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
 	mdelay(2000);		/* 2 seconds ?! */
+	printk("PDC202XX: %s channel reset.\n",
+		HWIF(drive)->channel ? "Secondary" : "Primary");
 }
 
-unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name)
+/*
+ * Since SUN Cobalt is attempting to do this operation, I should disclose
+ * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
+ * HOTSWAP ATA Infrastructure.
+ */
+static int pdc202xx_tristate (ide_drive_t * drive, int state)
 {
-	unsigned long high_16 = pci_resource_start(dev, 4);
-	byte udma_speed_flag	= inb(high_16 + 0x001f);
-	byte primary_mode	= inb(high_16 + 0x001a);
-	byte secondary_mode	= inb(high_16 + 0x001b);
-
-	if ((dev->device == PCI_DEVICE_ID_PROMISE_20262) ||
-	    (dev->device == PCI_DEVICE_ID_PROMISE_20265) ||
-	    (dev->device == PCI_DEVICE_ID_PROMISE_20267)) {
-		/*
-		 * software reset -  this is required because the bios
-		 * will set UDMA timing on if the hdd supports it. The
-		 * user may want to turn udma off. A bug in the pdc20262
-		 * is that it cannot handle a downgrade in timing from UDMA
-		 * to DMA. Disk accesses after issuing a set feature command
-		 * will result in errors. A software reset leaves the timing
-		 * registers intact, but resets the drives.
-		 */
-
-		OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
-		mdelay(100);
-		OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
-		mdelay(2000);	/* 2 seconds ?! */
+#if 0
+	ide_hwif_t *hwif	= HWIF(drive);
+	unsigned long high_16	= pci_resource_start(hwif->pci_dev, 4);
+	byte sc1f		= inb(high_16 + 0x001f);
+
+	if (!hwif)
+		return -EINVAL;
+
+//	hwif->bus_state = state;
+
+	if (state) {
+		outb(sc1f | 0x08, high_16 + 0x001f);
+	} else {
+		outb(sc1f & ~0x08, high_16 + 0x001f);
 	}
+#endif
+	return 0;
+}
+
+unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name)
+{
+	unsigned long high_16	= pci_resource_start(dev, 4);
+	byte udma_speed_flag	= IN_BYTE(high_16 + 0x001f);
+	byte primary_mode	= IN_BYTE(high_16 + 0x001a);
+	byte secondary_mode	= IN_BYTE(high_16 + 0x001b);
+	byte newchip		= 0;
 
 	if (dev->resource[PCI_ROM_RESOURCE].start) {
 		pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
 		printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
 	}
 
-	if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
-		byte irq = 0, irq2 = 0;
-		pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
-		pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2);	/* 0xbc */
-		if ((irq != irq2) &&
-		    (dev->device != PCI_DEVICE_ID_PROMISE_20265) &&
-		    (dev->device != PCI_DEVICE_ID_PROMISE_20267) &&
-		    (dev->device != PCI_DEVICE_ID_PROMISE_20268)) {
-			pci_write_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, irq);	/* 0xbc */
-			printk("%s: pci-config space interrupt mirror fixed.\n", name);
-		}
+	switch (dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20269:
+		case PCI_DEVICE_ID_PROMISE_20268R:
+		case PCI_DEVICE_ID_PROMISE_20268:
+			newchip = 1;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20267:
+		case PCI_DEVICE_ID_PROMISE_20265:
+			OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
+			mdelay(100);
+			OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
+			mdelay(2000);   /* 2 seconds ?! */
+			break;
+		case PCI_DEVICE_ID_PROMISE_20262:
+			/*
+			 * software reset -  this is required because the bios
+			 * will set UDMA timing on if the hdd supports it. The
+			 * user may want to turn udma off. A bug in the pdc20262
+			 * is that it cannot handle a downgrade in timing from
+			 * UDMA to DMA. Disk accesses after issuing a set
+			 * feature command will result in errors. A software
+			 * reset leaves the timing registers intact,
+			 * but resets the drives.
+			 */
+			OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
+			mdelay(100);
+			OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
+			mdelay(2000);	/* 2 seconds ?! */
+		default:
+			if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
+				byte irq = 0, irq2 = 0;
+				pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+				pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2);	/* 0xbc */
+				if (irq != irq2) {
+					pci_write_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, irq);	/* 0xbc */
+					printk("%s: pci-config space interrupt mirror fixed.\n", name);
+				}
+			}
+			break;
 	}
 
+	if (newchip)
+		goto fttk_tx_series;
+
 	printk("%s: (U)DMA Burst Bit %sABLED " \
 		"Primary %s Mode " \
 		"Secondary %s Mode.\n",
@@ -830,8 +1171,8 @@
 #ifdef CONFIG_PDC202XX_BURST
 	if (!(udma_speed_flag & 1)) {
 		printk("%s: FORCING BURST BIT 0x%02x -> 0x%02x ", name, udma_speed_flag, (udma_speed_flag|1));
-		outb(udma_speed_flag|1, high_16 + 0x001f);
-		printk("%sCTIVE\n", (inb(high_16 + 0x001f) & 1) ? "A" : "INA");
+		OUT_BYTE(udma_speed_flag|1, high_16 + 0x001f);
+		printk("%sCTIVE\n", (IN_BYTE(high_16 + 0x001f) & 1) ? "A" : "INA");
 	}
 #endif /* CONFIG_PDC202XX_BURST */
 
@@ -839,18 +1180,20 @@
 	if (!(primary_mode & 1)) {
 		printk("%s: FORCING PRIMARY MODE BIT 0x%02x -> 0x%02x ",
 			name, primary_mode, (primary_mode|1));
-		outb(primary_mode|1, high_16 + 0x001a);
-		printk("%s\n", (inb(high_16 + 0x001a) & 1) ? "MASTER" : "PCI");
+		OUT_BYTE(primary_mode|1, high_16 + 0x001a);
+		printk("%s\n", (IN_BYTE(high_16 + 0x001a) & 1) ? "MASTER" : "PCI");
 	}
 
 	if (!(secondary_mode & 1)) {
 		printk("%s: FORCING SECONDARY MODE BIT 0x%02x -> 0x%02x ",
 			name, secondary_mode, (secondary_mode|1));
-		outb(secondary_mode|1, high_16 + 0x001b);
-		printk("%s\n", (inb(high_16 + 0x001b) & 1) ? "MASTER" : "PCI");
+		OUT_BYTE(secondary_mode|1, high_16 + 0x001b);
+		printk("%s\n", (IN_BYTE(high_16 + 0x001b) & 1) ? "MASTER" : "PCI");
 	}
 #endif /* CONFIG_PDC202XX_MASTER */
 
+fttk_tx_series:
+
 #if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
 	if (!pdc202xx_proc) {
 		pdc202xx_proc = 1;
@@ -866,20 +1209,41 @@
 	unsigned short mask = (hwif->channel) ? (1<<11) : (1<<10);
 	unsigned short CIS;
 
-	pci_read_config_word(hwif->pci_dev, 0x50, &CIS);
-	return ((CIS & mask) ? 0 : 1);
+        switch(hwif->pci_dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20269:
+		case PCI_DEVICE_ID_PROMISE_20268:
+		case PCI_DEVICE_ID_PROMISE_20268R:
+			OUT_BYTE(0x0b, (hwif->dma_base + 1));
+			return (!(IN_BYTE((hwif->dma_base + 3)) & 0x04));
+		default:
+			pci_read_config_word(hwif->pci_dev, 0x50, &CIS);
+			return (!(CIS & mask));
+	}
 }
 
 void __init ide_init_pdc202xx (ide_hwif_t *hwif)
 {
-	hwif->tuneproc	= &pdc202xx_tune_drive;
-	hwif->speedproc	= &pdc202xx_tune_chipset;
-	hwif->quirkproc	= &pdc202xx_quirkproc;
-
-	if ((hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20262) ||
-	    (hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20265) ||
-	    (hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20267)) {
-		hwif->resetproc	= &pdc202xx_reset;
+	hwif->tuneproc  = &pdc202xx_tune_drive;
+	hwif->quirkproc = &pdc202xx_quirkproc;
+
+        switch(hwif->pci_dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20269:
+		case PCI_DEVICE_ID_PROMISE_20268:
+		case PCI_DEVICE_ID_PROMISE_20268R:
+			hwif->speedproc = &pdc202xx_new_tune_chipset;
+			hwif->resetproc = &pdc202xx_new_reset;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20267:
+		case PCI_DEVICE_ID_PROMISE_20265:
+		case PCI_DEVICE_ID_PROMISE_20262:
+			hwif->busproc   = &pdc202xx_tristate;
+			hwif->resetproc	= &pdc202xx_reset;
+		case PCI_DEVICE_ID_PROMISE_20246:
+			hwif->speedproc = &pdc202xx_tune_chipset;
+		default:
+			break;
 	}
 
 #undef CONFIG_PDC202XX_32_UNMASK
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/pdc4030.c linux/drivers/ide/pdc4030.c
--- v2.5.2/linux/drivers/ide/pdc4030.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/ide/pdc4030.c	Tue Jan 15 11:44:21 2002
@@ -183,7 +183,7 @@
 			"%s: Failed Promise read config!\n",hwif->name);
 		return 0;
 	}
-	ide_input_data(drive,&ident,SECTOR_WORDS);
+	ata_input_data(drive, &ident, SECTOR_WORDS);
 	if (ident.id[1] != 'P' || ident.id[0] != 'T') {
 		return 0;
 	}
@@ -300,8 +300,6 @@
 	}
 }
 
-
-
 /*
  * promise_read_intr() is the handler for disk read/multread interrupts
  */
@@ -335,7 +333,7 @@
 		nsect = sectors_avail;
 	sectors_avail -= nsect;
 	to = ide_map_buffer(rq, &flags);
-	idedisk_input_data(drive, to, nsect * SECTOR_WORDS);
+	ata_input_data(drive, to, nsect * SECTOR_WORDS);
 #ifdef DEBUG_READ
 	printk(KERN_DEBUG "%s:  promise_read: sectors(%ld-%ld), "
 	       "buf=0x%08lx, rem=%ld\n", drive->name, rq->sector,
@@ -393,7 +391,6 @@
 {
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 	struct request *rq = hwgroup->rq;
-	int i;
 
 	if (GET_STAT() & BUSY_STAT) {
 		if (time_before(jiffies, hwgroup->poll_timeout)) {
@@ -415,6 +412,61 @@
 }
 
 /*
+ * promise_multwrite() transfers a block of up to mcount sectors of data
+ * to a drive as part of a disk multiple-sector write operation.
+ *
+ * Returns 0 on success.
+ *
+ * Note that we may be called from two contexts - the do_rw_disk context
+ * and IRQ context. The IRQ can happen any time after we've output the
+ * full "mcount" number of sectors, so we must make sure we update the
+ * state _before_ we output the final part of the data!
+ */
+int promise_multwrite (ide_drive_t *drive, unsigned int mcount)
+{
+	ide_hwgroup_t   *hwgroup= HWGROUP(drive);
+	struct request  *rq = &hwgroup->wrq;
+
+	do {
+		char *buffer;
+		int nsect = rq->current_nr_sectors;
+		unsigned long flags;
+
+		if (nsect > mcount)
+			nsect = mcount;
+		mcount -= nsect;
+
+		buffer = ide_map_buffer(rq, &flags);
+		rq->sector += nsect;
+		rq->nr_sectors -= nsect;
+		rq->current_nr_sectors -= nsect;
+
+		/* Do we move to the next bh after this? */
+		if (!rq->current_nr_sectors) {
+			struct bio *bio = rq->bio->bi_next;
+
+			/* end early early we ran out of requests */
+			if (!bio) {
+				mcount = 0;
+			} else {
+				rq->bio = bio;
+				rq->current_nr_sectors = bio_sectors(bio);
+				rq->hard_cur_sectors = rq->current_nr_sectors;
+			}
+		}
+
+		/*
+		 * Ok, we're all setup for the interrupt
+		 * re-entering us on the last transfer.
+		 */
+		taskfile_output_data(drive, buffer, nsect<<7);
+		ide_unmap_buffer(buffer, &flags);
+	} while (mcount);
+
+	return 0;
+}
+
+/*
  * promise_write_pollfunc() is the handler for disk write completion polling.
  */
 static ide_startstop_t promise_write_pollfunc (ide_drive_t *drive)
@@ -434,7 +486,7 @@
 	/*
 	 * Now write out last 4 sectors and poll for not BUSY
 	 */
-	ide_multwrite(drive, 4);
+	promise_multwrite(drive, 4);
 	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
 	ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
 #ifdef DEBUG_WRITE
@@ -467,7 +519,7 @@
 	 * the polling strategy as defined above.
 	 */
 	if (rq->nr_sectors > 4) {
-		if (ide_multwrite(drive, rq->nr_sectors - 4))
+		if (promise_multwrite(drive, rq->nr_sectors - 4))
 			return ide_stopped;
 		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
 		ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);
@@ -477,7 +529,7 @@
 	 * There are 4 or fewer sectors to transfer, do them all in one go
 	 * and wait for NOT BUSY.
 	 */
-		if (ide_multwrite(drive, rq->nr_sectors))
+		if (promise_multwrite(drive, rq->nr_sectors))
 			return ide_stopped;
 		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
 		ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
@@ -494,11 +546,28 @@
  * already set up. It issues a READ or WRITE command to the Promise
  * controller, assuming LBA has been used to set up the block number.
  */
-ide_startstop_t do_pdc4030_io (ide_drive_t *drive, struct request *rq)
+ide_startstop_t do_pdc4030_io (ide_drive_t *drive, ide_task_t *task)
 {
+	struct request *rq	= HWGROUP(drive)->rq;
+	task_struct_t *taskfile	= (task_struct_t *) task->tfRegister;
+	ide_startstop_t startstop;
 	unsigned long timeout;
 	byte stat;
 
+	if (IDE_CONTROL_REG)
+		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);  /* clear nIEN */
+	SELECT_MASK(HWIF(drive), drive, 0);
+
+	OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
+	OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
+	/* refers to number of sectors to transfer */
+	OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
+	/* refers to sector offset or start sector */
+	OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
+	OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
+	OUT_BYTE(taskfile->device_head, IDE_SELECT_REG);
+	OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
+
 /* Check that it's a regular command. If not, bomb out early. */
 	if (!(rq->flags & REQ_CMD)) {
 		blk_dump_rq_flags(rq, "pdc4030 bad flags");
@@ -540,9 +609,8 @@
 		printk(KERN_ERR "%s: reading: No DRQ and not waiting - Odd!\n",
 			drive->name);
 		return ide_stopped;
-		break;
 
-	case WRITE:
+	case WRITE: {
 		ide_startstop_t startstop;
 		OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG);
 /*
@@ -561,11 +629,40 @@
 			__cli();	/* local CPU only */
 		HWGROUP(drive)->wrq = *rq; /* scratchpad */
 		return promise_write(drive);
-		break;
+	}
 
 	default:
 		printk(KERN_ERR "pdc4030: command not READ or WRITE! Huh?\n");
 		ide_end_request(0, HWGROUP(drive));
-		break;
+		return ide_stopped;
 	}
 }
+
+ide_startstop_t promise_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+	struct hd_drive_task_hdr taskfile;
+	ide_task_t		 args;
+
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+
+	taskfile.sector_count	= rq->nr_sectors;
+	taskfile.sector_number	= block;
+	taskfile.low_cylinder	= (block>>=8);
+	taskfile.high_cylinder	= (block>>=8);
+	taskfile.device_head	= ((block>>8)&0x0f)|drive->select.all;
+	taskfile.command	= (rq_data_dir(rq)==READ)?PROMISE_READ:PROMISE_WRITE;
+
+	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
+	memcpy(args.hobRegister, NULL, sizeof(struct hd_drive_hob_hdr));
+	args.command_type	= ide_cmd_type_parser(&args);
+	args.prehandler		= NULL;
+	args.handler		= NULL;
+	args.posthandler	= NULL;
+	args.rq			= (struct request *) rq;
+	args.block		= block;
+	rq->special		= NULL;
+	rq->special		= (ide_task_t *)&args;
+
+	return do_pdc4030_io(drive, &args);
+}
+
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/pdcadma.c linux/drivers/ide/pdcadma.c
--- v2.5.2/linux/drivers/ide/pdcadma.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/ide/pdcadma.c	Tue Jan 15 11:27:47 2002
@@ -0,0 +1,109 @@
+/*
+ * linux/drivers/ide/pdcadma.c		Version 0.01	June 21, 2001
+ *
+ * Copyright (C) 1999-2000		Andre Hedrick <andre@linux-ide.org>
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+
+#undef DISPLAY_PDCADMA_TIMINGS
+
+#if defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static int pdcadma_get_info(char *, char **, off_t, int);
+extern int (*pdcadma_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+extern char *ide_media_verbose(ide_drive_t *);
+static struct pci_dev *bmide_dev;
+
+static int pdcadma_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	u32 bibma = pci_resource_start(bmide_dev, 4);
+
+	p += sprintf(p, "\n                                PDC ADMA %04X Chipset.\n", bmide_dev->device);
+	p += sprintf(p, "UDMA\n");
+	p += sprintf(p, "PIO\n");
+
+	return p-buffer;	/* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+byte pdcadma_proc = 0;
+
+extern char *ide_xfer_verbose (byte xfer_rate);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+/*
+ * pdcadma_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
+ */
+
+int pdcadma_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+	switch (func) {
+		case ide_dma_check:
+			func = ide_dma_off_quietly;
+		default:
+			break;
+	}
+	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+unsigned int __init pci_init_pdcadma (struct pci_dev *dev, const char *name)
+{
+#if defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!pdcadma_proc) {
+		pdcadma_proc = 1;
+		bmide_dev = dev;
+		pdcadma_display_info = &pdcadma_get_info;
+	}
+#endif /* DISPLAY_PDCADMA_TIMINGS && CONFIG_PROC_FS */
+	return 0;
+}
+
+unsigned int __init ata66_pdcadma (ide_hwif_t *hwif)
+{
+	return 1;
+}
+
+void __init ide_init_pdcadma (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+	hwif->dma_base = 0;
+
+//	hwif->tuneproc = &pdcadma_tune_drive;
+//	hwif->speedproc = &pdcadma_tune_chipset;
+
+//	if (hwif->dma_base) {
+//		hwif->dmaproc = &pdcadma_dmaproc;
+//		hwif->autodma = 1;
+//	}
+}
+
+void __init ide_dmacapable_pdcadma (ide_hwif_t *hwif, unsigned long dmabase)
+{
+//	ide_setup_dma(hwif, dmabase, 8);
+}
+
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/piix.c linux/drivers/ide/piix.c
--- v2.5.2/linux/drivers/ide/piix.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/piix.c	Tue Jan 15 11:27:47 2002
@@ -402,7 +402,7 @@
 		}
 		dma_func = ide_dma_off_quietly;
 		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x002F) {
+			if (id->dma_ultra & 0x003F) {
 				/* Force if Capable UltraDMA */
 				dma_func = piix_config_drive_for_dma(drive);
 				if ((id->field_valid & 2) &&
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/qd65xx.c linux/drivers/ide/qd65xx.c
--- v2.5.2/linux/drivers/ide/qd65xx.c	Fri Sep  7 09:28:38 2001
+++ linux/drivers/ide/qd65xx.c	Tue Jan 15 11:27:47 2002
@@ -1,14 +1,15 @@
 /*
- *  linux/drivers/ide/qd65xx.c		Version 0.06	Aug 3, 2000
+ *  linux/drivers/ide/qd65xx.c		Version 0.07	Sep 30, 2001
  *
- *  Copyright (C) 1996-2000  Linus Torvalds & author (see below)
+ *  Copyright (C) 1996-2001  Linus Torvalds & author (see below)
  */
 
 /*
  *  Version 0.03	Cleaned auto-tune, added probe
  *  Version 0.04	Added second channel tuning
  *  Version 0.05	Enhanced tuning ; added qd6500 support
- *  Version 0.06	added dos driver's list
+ *  Version 0.06	Added dos driver's list
+ *  Version 0.07	Second channel bug fix 
  *
  * QDI QD6500/QD6580 EIDE controller fast support
  *
@@ -67,6 +68,7 @@
  *        qd6500: 1100
  *        qd6580: either 1010 or 0101
  *
+ *
  * base+0x02: Timer2 (qd6580 only)
  *
  *
@@ -137,12 +139,12 @@
 {
 	byte active_cycle,recovery_cycle;
 
-	if (system_bus_clock()<=33) {
-		active_cycle =   9  - IDE_IN(active_time   * system_bus_clock() / 1000 + 1, 2, 9);
-		recovery_cycle = 15 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 0, 15);
+	if (ide_system_bus_speed()<=33) {
+		active_cycle =   9  - IDE_IN(active_time   * ide_system_bus_speed() / 1000 + 1, 2, 9);
+		recovery_cycle = 15 - IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 0, 15);
 	} else {
-		active_cycle =   8  - IDE_IN(active_time   * system_bus_clock() / 1000 + 1, 1, 8);
-		recovery_cycle = 18 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 3, 18);
+		active_cycle =   8  - IDE_IN(active_time   * ide_system_bus_speed() / 1000 + 1, 1, 8);
+		recovery_cycle = 18 - IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 3, 18);
 	}
 
 	return((recovery_cycle<<4) | 0x08 | active_cycle);
@@ -156,8 +158,8 @@
 
 static byte qd6580_compute_timing (int active_time, int recovery_time)
 {
-	byte active_cycle   = 17-IDE_IN(active_time   * system_bus_clock() / 1000 + 1, 2, 17);
-	byte recovery_cycle = 15-IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 2, 15);
+	byte active_cycle   = 17-IDE_IN(active_time   * ide_system_bus_speed() / 1000 + 1, 2, 17);
+	byte recovery_cycle = 15-IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 2, 15);
 
 	return((recovery_cycle<<4) | active_cycle);
 }
@@ -427,7 +429,8 @@
 				ide_hwifs[i].tuneproc = &qd6580_tune_drive;
 
 				for (j=0;j<2;j++) {
-					ide_hwifs[i].drives[j].drive_data = QD6580_DEF_DATA;
+					ide_hwifs[i].drives[j].drive_data =
+					       i?QD6580_DEF_DATA2:QD6580_DEF_DATA;
 					ide_hwifs[i].drives[j].io_32bit = 1;
 				}
 			}
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/qd65xx.h linux/drivers/ide/qd65xx.h
--- v2.5.2/linux/drivers/ide/qd65xx.h	Fri Sep  7 09:28:38 2001
+++ linux/drivers/ide/qd65xx.h	Tue Jan 15 11:27:47 2002
@@ -29,7 +29,7 @@
 
 #define QD_CONTR_SEC_DISABLED	0x01
 
-#define QD_ID3			(config & QD_CONFIG_ID3)
+#define QD_ID3			((config & QD_CONFIG_ID3)!=0)
 
 #define QD_CONFIG(hwif)		((hwif)->config_data & 0x00ff)
 #define QD_CONTROL(hwif)	(((hwif)->config_data & 0xff00) >> 8)
@@ -39,6 +39,7 @@
 
 #define QD6500_DEF_DATA		((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0c : 0x08))
 #define QD6580_DEF_DATA		((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0a : 0x00))
+#define QD6580_DEF_DATA2	((QD_TIM2_PORT<<8) | (QD_ID3 ? 0x0a : 0x00))
 #define QD_DEF_CONTR		(0x40 | ((control & 0x02) ? 0x9f : 0x1f))
 
 #define QD_TESTVAL		0x19	/* safe value */
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/serverworks.c linux/drivers/ide/serverworks.c
--- v2.5.2/linux/drivers/ide/serverworks.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/serverworks.c	Tue Jan 15 11:27:47 2002
@@ -1,16 +1,26 @@
 /*
- * linux/drivers/ide/serverworks.c		Version 0.2	17 Oct 2000
+ * linux/drivers/ide/serverworks.c		Version 0.3	26 Oct 2001
  *
- *  Copyright (C) 2000 Cobalt Networks, Inc. <asun@cobalt.com>
- *  May be copied or modified under the terms of the GNU General Public License
+ * May be copied or modified under the terms of the GNU General Public License
  *
- *  interface borrowed from alim15x3.c:
- *  Copyright (C) 1998-2000 Michel Aubry, Maintainer
- *  Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
+ * Copyright (C) 1998-2000 Michel Aubry
+ * Copyright (C) 1998-2000 Andrzej Krzysztofowicz
+ * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
+ * Portions copyright (c) 2001 Sun Microsystems
  *
- *  Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
  *
- *  IDE support for the ServerWorks OSB4 IDE chipset
+ * RCC/ServerWorks IDE driver for Linux
+ *
+ *   OSB4: `Open South Bridge' IDE Interface (fn 1)
+ *         supports UDMA mode 2 (33 MB/s)
+ *
+ *   CSB5: `Champion South Bridge' IDE Interface (fn 1)
+ *         all revisions support UDMA mode 4 (66 MB/s)
+ *         revision A2.0 and up support UDMA mode 5 (100 MB/s)
+ *
+ *         *** The CSB5 does not provide ANY register ***
+ *         *** to detect 80-conductor cable presence. ***
+ *
  *
  * here's the default lspci:
  *
@@ -83,15 +93,15 @@
 
 #include "ide_modes.h"
 
-#define SVWKS_DEBUG_DRIVE_INFO		0
-
-#define DISPLAY_SVWKS_TIMINGS
+#define DISPLAY_SVWKS_TIMINGS	1
+#undef SVWKS_DEBUG_DRIVE_INFO
 
 #if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
 
 static struct pci_dev *bmide_dev;
+static byte svwks_revision = 0;
 
 static int svwks_get_info(char *, char **, off_t, int);
 extern int (*svwks_display_info)(char *, char **, off_t, int); /* ide-proc.c */
@@ -103,7 +113,7 @@
 	u32 bibma = pci_resource_start(bmide_dev, 4);
 	u32 reg40, reg44;
 	u16 reg48, reg56;
-	u8  c0 = 0, c1 = 0, reg54;
+	u8  reg54, c0=0, c1=0;
 
 	pci_read_config_dword(bmide_dev, 0x40, &reg40);
 	pci_read_config_dword(bmide_dev, 0x44, &reg44);
@@ -120,20 +130,23 @@
 
 	switch(bmide_dev->device) {
 		case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
-			p += sprintf(p, "\n                                ServerWorks CSB5 Chipset.\n");
+			p += sprintf(p, "\n                            "
+				     "ServerWorks CSB5 Chipset (rev %02x)\n",
+				     svwks_revision);
 			break;
-		case PCI_DEVICE_ID_SERVERWORKS_OSB4:
-			p += sprintf(p, "\n                                ServerWorks OSB4 Chipset.\n");
+		case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE:
+			p += sprintf(p, "\n                            "
+				     "ServerWorks OSB4 Chipset (rev %02x)\n",
+				     svwks_revision);
 			break;
 		default:
-			p += sprintf(p, "\n                                ServerWorks 0x%04x Chipset.\n", bmide_dev->device);
+			p += sprintf(p, "\n                            "
+				     "ServerWorks %04x Chipset (rev %02x)\n",
+				     bmide_dev->device, svwks_revision);
 			break;
 	}
 
 	p += sprintf(p, "------------------------------- General Status ---------------------------------\n");
-#if 0
-	p += sprintf(p, "                                     : %s\n", "str");
-#endif
 	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
 	p += sprintf(p, "                %sabled                         %sabled\n",
 			(c0&0x80) ? "dis" : " en",
@@ -191,11 +204,7 @@
 				((reg44&0x00210000)==0x00210000)?"1":
 				((reg44&0x00770000)==0x00770000)?"0":
 				((reg44&0x00FF0000)==0x00FF0000)?"X":"?");
-#if 0
-	if (bmide_dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
-		p += sprintf(p, "PIO  enabled:   %s                %s               %s                 %s\n",
-	if (bmide_dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4)
-#endif
+
 		p += sprintf(p, "PIO  enabled:   %s                %s               %s                 %s\n",
 			((reg40&0x00002000)==0x00002000)?"4":
 				((reg40&0x00002200)==0x00002200)?"3":
@@ -221,7 +230,7 @@
 }
 #endif  /* defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) */
 
-static byte svwks_revision = 0;
+#define SVWKS_CSB5_REVISION_NEW	0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
 
 byte svwks_proc = 0;
 
@@ -292,6 +301,7 @@
 			pio_timing |= pio_modes[speed - XFER_PIO_0];
 			csb5_pio   |= ((speed - XFER_PIO_0) << (4*drive->dn));
 			break;
+
 #ifdef CONFIG_BLK_DEV_IDEDMA
 		case XFER_MW_DMA_2:
 		case XFER_MW_DMA_1:
@@ -307,9 +317,9 @@
 		case XFER_UDMA_2:
 		case XFER_UDMA_1:
 		case XFER_UDMA_0:
-			pio_timing |= pio_modes[pio];
-			csb5_pio   |= (pio << (4*drive->dn));
-			dma_timing |= dma_modes[2];
+			pio_timing   |= pio_modes[pio];
+			csb5_pio     |= (pio << (4*drive->dn));
+			dma_timing   |= dma_modes[2];
 			ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << (4*unit));
 			ultra_enable |= (0x01 << drive->dn);
 #endif
@@ -322,9 +332,9 @@
 		drive->name, ultra_timing, dma_timing, pio_timing);
 #endif
 
-#if OSB4_DEBUG_DRIVE_INFO
+#if SVWKS_DEBUG_DRIVE_INFO
 	printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn);
-#endif /* OSB4_DEBUG_DRIVE_INFO */
+#endif /* SVWKS_DEBUG_DRIVE_INFO */
 
 	if (!drive->init_speed)
 		drive->init_speed = speed;
@@ -338,11 +348,10 @@
 	pci_write_config_byte(dev, drive_pci3, ultra_timing);
 	pci_write_config_byte(dev, 0x54, ultra_enable);
 	
-	if (speed > XFER_PIO_4) {
+	if (speed > XFER_PIO_4)
 		outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
-	} else {
+	else
 		outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
-	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
 	err = ide_config_drive_speed(drive, speed);
@@ -354,25 +363,24 @@
 {
 	unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
 	unsigned short xfer_pio = drive->id->eide_pio_modes;
-	byte			timing, speed, pio;
+	byte timing, speed, pio;
 
 	pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
 
 	if (xfer_pio> 4)
 		xfer_pio = 0;
 
-	if (drive->id->eide_pio_iordy > 0) {
+	if (drive->id->eide_pio_iordy > 0)
 		for (xfer_pio = 5;
 			xfer_pio>0 &&
 			drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
 			xfer_pio--);
-	} else {
+	else
 		xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
 			   (drive->id->eide_pio_modes & 2) ? 0x04 :
 			   (drive->id->eide_pio_modes & 1) ? 0x03 :
 			   (drive->id->tPIO & 2) ? 0x02 :
 			   (drive->id->tPIO & 1) ? 0x01 : xfer_pio;
-	}
 
 	timing = (xfer_pio >= pio) ? xfer_pio : pio;
 
@@ -407,12 +415,10 @@
 {
 	struct hd_driveid *id	= drive->id;
 	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-	byte udma_66		= eighty_ninty_three(drive);
-	byte			speed;
-
-	int ultra66		= (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
-	/* need specs to figure out if osb4 is capable of ata/66/100 */
-	int ultra100		= (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
+	byte udma_66	= eighty_ninty_three(drive);
+	int ultra66	= (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
+	int ultra100 	= (ultra66 && svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 1 : 0;
+	byte speed;
 
 	if ((id->dma_ultra & 0x0020) && (udma_66) && (ultra100)) {
 		speed = XFER_UDMA_5;
@@ -458,7 +464,7 @@
 		}
 		dma_func = ide_dma_off_quietly;
 		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x002F) {
+			if (id->dma_ultra & 0x003F) {
 				/* Force if Capable UltraDMA */
 				dma_func = config_chipset_for_dma(drive);
 				if ((id->field_valid & 2) &&
@@ -499,7 +505,41 @@
 	switch (func) {
 		case ide_dma_check:
 			return config_drive_xfer_rate(drive);
-		default :
+		case ide_dma_end:
+		{
+			ide_hwif_t *hwif		= HWIF(drive);
+			unsigned long dma_base		= hwif->dma_base;
+	
+			if(inb(dma_base+0x02)&1)
+			{
+#if 0		
+				int i;
+				printk(KERN_ERR "Curious - OSB4 thinks the DMA is still running.\n");
+				for(i=0;i<10;i++)
+				{
+					if(!(inb(dma_base+0x02)&1))
+					{
+						printk(KERN_ERR "OSB4 now finished.\n");
+						break;
+					}
+					udelay(5);
+				}
+#endif		
+				printk(KERN_CRIT "Serverworks OSB4 in impossible state.\n");
+				printk(KERN_CRIT "Disable UDMA or if you are using Seagate then try switching disk types\n");
+				printk(KERN_CRIT "on this controller. Please report this event to osb4-bug@ide.cabal.tm\n");
+#if 0		
+				/* Panic might sys_sync -> death by corrupt disk */
+				panic("OSB4: continuing might cause disk corruption.\n");
+#else
+				printk(KERN_CRIT "OSB4: continuing might cause disk corruption.\n");
+				while(1)
+					cpu_relax();
+#endif				
+			}
+			/* and drop through */
+		}
+		default:
 			break;
 	}
 	/* Other cases are done by generic IDE-DMA code. */
@@ -509,30 +549,43 @@
 
 unsigned int __init pci_init_svwks (struct pci_dev *dev, const char *name)
 {
-	unsigned int reg64;
+	unsigned int reg;
+	byte btr;
 
+	/* save revision id to determine DMA capability */
 	pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision);
 
-	if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
-		isa_dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
+	/* force Master Latency Timer value to 64 PCICLKs */
+	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
 
-		pci_read_config_dword(isa_dev, 0x64, &reg64);
-#ifdef DEBUG
-		printk("%s: reg64 == 0x%08x\n", name, reg64);
-#endif
+	/* OSB4 : South Bridge and IDE */
+	if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
+		isa_dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
+			  PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
+		if (isa_dev) {
+			pci_read_config_dword(isa_dev, 0x64, &reg);
+			reg &= ~0x00002000; /* disable 600ns interrupt mask */
+			reg |=  0x00004000; /* enable UDMA/33 support */
+			pci_write_config_dword(isa_dev, 0x64, reg);
+		}
+	}
 
-//		reg64 &= ~0x0000A000;
-//#ifdef CONFIG_SMP
-//		reg64 |= 0x00008000;
-//#endif
-	/* Assume the APIC was set up properly by the BIOS for now . If it
-	   wasnt we need to do a fix up _way_ earlier. Bits 15,10,3 control
-	   APIC enable, routing and decode */
-	   
-		reg64 &= ~0x00002000;	
-		pci_write_config_dword(isa_dev, 0x64, reg64);
+	/* setup CSB5 : South Bridge and IDE */
+	else if (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) {
+		/* setup the UDMA Control register
+		 *
+		 * 1. clear bit 6 to enable DMA
+		 * 2. enable DMA modes with bits 0-1
+		 *      00 : legacy
+		 *      01 : udma2
+		 *      10 : udma2/udma4
+		 *      11 : udma2/udma4/udma5
+		 */
+		pci_read_config_byte(dev, 0x5A, &btr);
+		btr &= ~0x40;
+		btr |= (svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2;
+		pci_write_config_byte(dev, 0x5A, btr);
 	}
-	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
 
 #if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
 	if (!svwks_proc) {
@@ -551,26 +604,46 @@
  * Bit 14 clear = primary IDE channel does not have 80-pin cable.
  * Bit 14 set   = primary IDE channel has 80-pin cable.
  */
-
 static unsigned int __init ata66_svwks_dell (ide_hwif_t *hwif)
 {
-	struct pci_dev *dev	= hwif->pci_dev;
-	if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL        &&
-	    dev->vendor           == PCI_VENDOR_ID_SERVERWORKS &&
-	    dev->device           == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
+	struct pci_dev *dev = hwif->pci_dev;
+	if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
+	    dev->vendor	== PCI_VENDOR_ID_SERVERWORKS &&
+	    dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
 		return ((1 << (hwif->channel + 14)) &
 			dev->subsystem_device) ? 1 : 0;
-
 	return 0;
+}
 
+/* Sun Cobalt Alpine hardware avoids the 80-pin cable
+ * detect issue by attaching the drives directly to the board.
+ * This check follows the Dell precedent (how scary is that?!)
+ *
+ * WARNING: this only works on Alpine hardware!
+ */
+static unsigned int __init ata66_svwks_cobalt (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev = hwif->pci_dev;
+	if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN &&
+	    dev->vendor	== PCI_VENDOR_ID_SERVERWORKS &&
+	    dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
+		return ((1 << (hwif->channel + 14)) &
+			dev->subsystem_device) ? 1 : 0;
+	return 0;
 }
 
 unsigned int __init ata66_svwks (ide_hwif_t *hwif)
 {
-	struct pci_dev *dev	= hwif->pci_dev;
+	struct pci_dev *dev = hwif->pci_dev;
+
+	/* Dell PowerEdge */
 	if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL)
 		return ata66_svwks_dell (hwif);
-	
+
+	/* Cobalt Alpine */
+	if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN)
+		return ata66_svwks_cobalt (hwif);
+
 	return 0;
 }
 
@@ -586,9 +659,7 @@
 	hwif->drives[0].autotune = 1;
 	hwif->drives[1].autotune = 1;
 	hwif->autodma = 0;
-	return;
 #else /* CONFIG_BLK_DEV_IDEDMA */
-
 	if (hwif->dma_base) {
 		if (!noautodma)
 			hwif->autodma = 1;
diff -u --recursive --new-file v2.5.2/linux/drivers/ide/slc90e66.c linux/drivers/ide/slc90e66.c
--- v2.5.2/linux/drivers/ide/slc90e66.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ide/slc90e66.c	Tue Jan 15 11:27:47 2002
@@ -86,8 +86,13 @@
          * at that point bibma+0x2 et bibma+0xa are byte registers
          * to investigate:
          */
+#ifdef __mips__	/* only for mips? */
+	c0 = inb_p(bibma + 0x02);
+	c1 = inb_p(bibma + 0x0a);
+#else
 	c0 = inb_p((unsigned short)bibma + 0x02);
 	c1 = inb_p((unsigned short)bibma + 0x0a);
+#endif
 
 	p += sprintf(p, "                                SLC90E66 Chipset.\n");
 	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
@@ -253,7 +258,9 @@
 		case XFER_MW_DMA_2:
 		case XFER_MW_DMA_1:
 		case XFER_SW_DMA_2:	break;
+#if 0	/* allow PIO modes */
 		default:		return -1;
+#endif
 	}
 
 	if (speed >= XFER_UDMA_0) {
@@ -291,6 +298,13 @@
 	byte speed		= 0;
 	byte udma_66		= eighty_ninty_three(drive);
 
+#if 1 /* allow PIO modes */
+	if (!HWIF(drive)->autodma) {
+		speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
+		(void) slc90e66_tune_chipset(drive, speed);
+		return ((int) ide_dma_off_quietly);
+	}
+#endif
 	if ((id->dma_ultra & 0x0010) && (ultra)) {
 		speed = (udma_66) ? XFER_UDMA_4 : XFER_UDMA_2;
 	} else if ((id->dma_ultra & 0x0008) && (ultra)) {
diff -u --recursive --new-file v2.5.2/linux/drivers/ieee1394/raw1394.c linux/drivers/ieee1394/raw1394.c
--- v2.5.2/linux/drivers/ieee1394/raw1394.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/ieee1394/raw1394.c	Tue Jan 15 10:52:11 2002
@@ -915,7 +915,7 @@
 {
         struct file_info *fi;
 
-        if (MINOR(inode->i_rdev)) {
+        if (minor(inode->i_rdev)) {
                 return -ENXIO;
         }
 
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/avmb1/b1pci.c linux/drivers/isdn/avmb1/b1pci.c
--- v2.5.2/linux/drivers/isdn/avmb1/b1pci.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/isdn/avmb1/b1pci.c	Thu Jan 17 14:04:15 2002
@@ -67,26 +67,6 @@
 
 	card->interrupt = 0;
 }
-/* ------------------------------------------------------------- */
-
-static void b1pci_remove_ctr(struct capi_ctr *ctrl)
-{
-	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
-	avmcard *card = cinfo->card;
-	unsigned int port = card->port;
-
-	b1_reset(port);
-	b1_reset(port);
-
-	di->detach_ctr(ctrl);
-	free_irq(card->irq, card);
-	release_region(card->port, AVMB1_PORTLEN);
-	ctrl->driverdata = 0;
-	kfree(card->ctrlinfo);
-	kfree(card);
-
-	MOD_DEC_USE_COUNT;
-}
 
 /* ------------------------------------------------------------- */
 
@@ -118,20 +98,18 @@
 
 	MOD_INC_USE_COUNT;
 
-	card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
-
+	retval = -ENOMEM;
+	card = kmalloc(sizeof(avmcard), GFP_KERNEL);
 	if (!card) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err;
 	}
 	memset(card, 0, sizeof(avmcard));
-        cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
+
+        cinfo = kmalloc(sizeof(avmctrl_info), GFP_KERNEL);
 	if (!cinfo) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err_kfree;
 	}
 	memset(cinfo, 0, sizeof(avmctrl_info));
 	card->ctrlinfo = cinfo;
@@ -140,51 +118,38 @@
 	card->port = p->port;
 	card->irq = p->irq;
 	card->cardtype = avm_b1pci;
-
-	if (check_region(card->port, AVMB1_PORTLEN)) {
+	
+	if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
 		printk(KERN_WARNING
 		       "%s: ports 0x%03x-0x%03x in use.\n",
 		       driver->name, card->port, card->port + AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		goto err_kfree_ctrlinfo;
 	}
 	b1_reset(card->port);
-	if ((retval = b1_detect(card->port, card->cardtype)) != 0) {
+	retval = b1_detect(card->port, card->cardtype);
+	if (retval) {
 		printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
-					driver->name, card->port, retval);
-	        kfree(card->ctrlinfo);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EIO;
+		       driver->name, card->port, retval);
+		retval = -EIO;
+		goto err_release_region;
 	}
 	b1_reset(card->port);
 	b1_getrevision(card);
-
-	request_region(p->port, AVMB1_PORTLEN, card->name);
-
+	
 	retval = request_irq(card->irq, b1pci_interrupt, SA_SHIRQ, card->name, card);
 	if (retval) {
 		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
-				driver->name, card->irq);
-		release_region(card->port, AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		       driver->name, card->irq);
+		retval = -EBUSY;
+		goto err_release_region;
 	}
-
+	
 	cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
 	if (!cinfo->capi_ctrl) {
 		printk(KERN_ERR "%s: attach controller failed.\n",
-				driver->name);
-		free_irq(card->irq, card);
-		release_region(card->port, AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		       driver->name);
+		retval = -EBUSY;
+		goto err_free_irq;
 	}
 
 	if (card->revision >= 4) {
@@ -198,6 +163,37 @@
 	}
 
 	return 0;
+
+ err_free_irq:
+	free_irq(card->irq, card);
+ err_release_region:
+	release_region(card->port, AVMB1_PORTLEN);
+ err_kfree_ctrlinfo:
+	kfree(card->ctrlinfo);
+ err_kfree:
+	kfree(card);
+ err:
+	MOD_DEC_USE_COUNT;
+	return retval;
+}
+
+static void b1pci_remove_ctr(struct capi_ctr *ctrl)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
+	unsigned int port = card->port;
+
+	b1_reset(port);
+	b1_reset(port);
+
+	di->detach_ctr(ctrl);
+	free_irq(card->irq, card);
+	release_region(card->port, AVMB1_PORTLEN);
+	ctrl->driverdata = 0;
+	kfree(card->ctrlinfo);
+	kfree(card);
+
+	MOD_DEC_USE_COUNT;
 }
 
 /* ------------------------------------------------------------- */
@@ -226,25 +222,6 @@
 
 /* ------------------------------------------------------------- */
 
-static void b1pciv4_remove_ctr(struct capi_ctr *ctrl)
-{
-	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
-	avmcard *card = cinfo->card;
-
- 	b1dma_reset(card);
-
-	div4->detach_ctr(ctrl);
-	free_irq(card->irq, card);
-	iounmap(card->mbase);
-	release_region(card->port, AVMB1_PORTLEN);
-	ctrl->driverdata = 0;
-	kfree(card->ctrlinfo);
-        avmcard_dma_free(card->dma);
-	kfree(card);
-
-	MOD_DEC_USE_COUNT;
-}
-
 static char *b1pciv4_procinfo(struct capi_ctr *ctrl)
 {
 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
@@ -274,28 +251,23 @@
 
 	MOD_INC_USE_COUNT;
 
-	card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
-
+	retval = -ENOMEM;
+	card = kmalloc(sizeof(avmcard), GFP_KERNEL);
 	if (!card) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err;
 	}
 	memset(card, 0, sizeof(avmcard));
+
         card->dma = avmcard_dma_alloc(driver->name, dev, 2048+128, 2048+128);
 	if (!card->dma) {
 		printk(KERN_WARNING "%s: dma alloc.\n", driver->name);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err_kfree;
 	}
-        cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
+        cinfo = kmalloc(sizeof(avmctrl_info), GFP_KERNEL);
 	if (!cinfo) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err_dma_free;
 	}
 	memset(cinfo, 0, sizeof(avmctrl_info));
 	card->ctrlinfo = cinfo;
@@ -306,69 +278,47 @@
 	card->membase = p->membase;
 	card->cardtype = avm_b1pci;
 
-	if (check_region(card->port, AVMB1_PORTLEN)) {
+	if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
 		printk(KERN_WARNING
 		       "%s: ports 0x%03x-0x%03x in use.\n",
 		       driver->name, card->port, card->port + AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		retval = -EBUSY;
+		goto err_kfree_ctrlinfo;
 	}
 
 	card->mbase = ioremap_nocache(card->membase, 64);
 	if (!card->mbase) {
 		printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
 					driver->name, card->membase);
-	        kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EIO;
+		retval = -EIO;
+		goto err_release_region;
 	}
 
 	b1dma_reset(card);
 
-	if ((retval = b1pciv4_detect(card)) != 0) {
+	retval = b1pciv4_detect(card);
+	if (retval) {
 		printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
 					driver->name, card->port, retval);
-                iounmap(card->mbase);
-	        kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EIO;
+		retval = -EIO;
+		goto err_unmap;
 	}
 	b1dma_reset(card);
 	b1_getrevision(card);
 
-	request_region(p->port, AVMB1_PORTLEN, card->name);
-
 	retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card);
 	if (retval) {
 		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
 				driver->name, card->irq);
-                iounmap(card->mbase);
-		release_region(card->port, AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		retval = -EBUSY;
+		goto err_unmap;
 	}
 
 	cinfo->capi_ctrl = div4->attach_ctr(driver, card->name, cinfo);
 	if (!cinfo->capi_ctrl) {
 		printk(KERN_ERR "%s: attach controller failed.\n", driver->name);
-                iounmap(card->mbase);
-		free_irq(card->irq, card);
-		release_region(card->port, AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		retval = -EBUSY;
+		goto err_free_irq;
 	}
 	card->cardnr = cinfo->capi_ctrl->cnr;
 
@@ -378,6 +328,42 @@
 		card->membase, card->revision);
 
 	return 0;
+
+ err_free_irq:
+	free_irq(card->irq, card);
+ err_unmap:
+	iounmap(card->mbase);
+ err_release_region:
+	release_region(card->port, AVMB1_PORTLEN);
+ err_kfree_ctrlinfo:
+	kfree(card->ctrlinfo);
+ err_dma_free:
+	avmcard_dma_free(card->dma);
+ err_kfree:
+	kfree(card);
+ err:
+	MOD_DEC_USE_COUNT;
+	return retval;
+
+}
+
+static void b1pciv4_remove_ctr(struct capi_ctr *ctrl)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
+
+ 	b1dma_reset(card);
+
+	div4->detach_ctr(ctrl);
+	free_irq(card->irq, card);
+	iounmap(card->mbase);
+	release_region(card->port, AVMB1_PORTLEN);
+	ctrl->driverdata = 0;
+	kfree(card->ctrlinfo);
+        avmcard_dma_free(card->dma);
+	kfree(card);
+
+	MOD_DEC_USE_COUNT;
 }
 
 /* ------------------------------------------------------------- */
@@ -402,8 +388,6 @@
 
 #endif /* CONFIG_ISDN_DRV_AVMB1_B1PCIV4 */
 
-static int ncards = 0;
-
 static int __devinit b1pci_probe(struct pci_dev *dev,
 				 const struct pci_device_id *ent)
 {
@@ -470,6 +454,7 @@
 	struct capi_driver *driverv4 = &b1pciv4_driver;
 #endif
 	char *p;
+	int ncards;
 
 	MOD_INC_USE_COUNT;
 
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/avmb1/c4.c linux/drivers/isdn/avmb1/c4.c
--- v2.5.2/linux/drivers/isdn/avmb1/c4.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/isdn/avmb1/c4.c	Thu Jan 17 14:04:15 2002
@@ -1133,28 +1133,23 @@
 
 	MOD_INC_USE_COUNT;
 
-	card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
-
+	retval = -ENOMEM;
+	card = kmalloc(sizeof(avmcard), GFP_ATOMIC);
 	if (!card) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err;
 	}
 	memset(card, 0, sizeof(avmcard));
+
         card->dma = avmcard_dma_alloc(driver->name, dev, 2048+128, 2048+128);
 	if (!card->dma) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err_kfree;
 	}
         cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info)*4, GFP_ATOMIC);
 	if (!cinfo) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err_dma_free;
 	}
 	memset(cinfo, 0, sizeof(avmctrl_info)*4);
 	card->ctrlinfo = cinfo;
@@ -1168,53 +1163,37 @@
 	card->membase = p->membase;
 	card->cardtype = nr == 4 ? avm_c4 : avm_c2;
 
-	if (check_region(card->port, AVMB1_PORTLEN)) {
+	if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
 		printk(KERN_WARNING
 		       "%s: ports 0x%03x-0x%03x in use.\n",
 		       driver->name, card->port, card->port + AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		retval = -EBUSY;
+		goto err_kfree_ctrlinfo;
 	}
 
 	card->mbase = ioremap_nocache(card->membase, 128);
 	if (card->mbase == 0) {
 		printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
 					driver->name, card->membase);
-	        kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EIO;
+		retval = -EIO;
+		goto err_release_region;
 	}
 
-	if ((retval = c4_detect(card)) != 0) {
+	retval = c4_detect(card);
+	if (retval != 0) {
 		printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
 					driver->name, card->port, retval);
-                iounmap(card->mbase);
-	        kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EIO;
+		retval = -EIO;
+		goto err_unmap;
 	}
 	c4_reset(card);
 
-	request_region(p->port, AVMB1_PORTLEN, card->name);
-
 	retval = request_irq(card->irq, c4_interrupt, SA_SHIRQ, card->name, card);
 	if (retval) {
 		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
 				driver->name, card->irq);
-                iounmap(card->mbase);
-		release_region(card->port, AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		retval = -EBUSY;
+		goto err_unmap;
 	}
 
 	for (i=0; i < nr ; i++) {
@@ -1228,14 +1207,7 @@
 				cinfo = &card->ctrlinfo[i];
 				di->detach_ctr(cinfo->capi_ctrl);
 			}
-                	iounmap(card->mbase);
-			free_irq(card->irq, card);
-			release_region(card->port, AVMB1_PORTLEN);
-                        avmcard_dma_free(card->dma);
-	        	kfree(card->ctrlinfo);
-			kfree(card);
-	        	MOD_DEC_USE_COUNT;
-			return -EBUSY;
+			goto err_free_irq;
 		}
 		if (i == 0)
 			card->cardnr = cinfo->capi_ctrl->cnr;
@@ -1246,6 +1218,22 @@
 		driver->name, nr, card->port, card->irq, card->membase);
 
 	return 0;
+
+ err_free_irq:
+	free_irq(card->irq, card);
+ err_unmap:
+	iounmap(card->mbase);
+ err_release_region:
+	release_region(card->port, AVMB1_PORTLEN);
+ err_kfree_ctrlinfo:
+	kfree(card->ctrlinfo);
+ err_dma_free:
+	avmcard_dma_free(card->dma);
+ err_kfree:
+	kfree(card);
+ err:
+	MOD_DEC_USE_COUNT;
+	return retval;
 }
 
 /* ------------------------------------------------------------- */
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/avmb1/t1pci.c linux/drivers/isdn/avmb1/t1pci.c
--- v2.5.2/linux/drivers/isdn/avmb1/t1pci.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/isdn/avmb1/t1pci.c	Thu Jan 17 14:04:15 2002
@@ -49,27 +49,6 @@
 
 /* ------------------------------------------------------------- */
 
-static void t1pci_remove_ctr(struct capi_ctr *ctrl)
-{
-	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
-	avmcard *card = cinfo->card;
-
- 	b1dma_reset(card);
-
-	di->detach_ctr(ctrl);
-	free_irq(card->irq, card);
-	iounmap(card->mbase);
-	release_region(card->port, AVMB1_PORTLEN);
-	ctrl->driverdata = 0;
-	kfree(card->ctrlinfo);
-	avmcard_dma_free(card->dma);
-	kfree(card);
-
-	MOD_DEC_USE_COUNT;
-}
-
-/* ------------------------------------------------------------- */
-
 static int t1pci_add_card(struct capi_driver *driver,
                           struct capicardparams *p,
 	                  struct pci_dev *dev)
@@ -80,28 +59,22 @@
 
 	MOD_INC_USE_COUNT;
 
-	card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
-
+	retval = -ENOMEM;
+	card = kmalloc(sizeof(avmcard), GFP_KERNEL);
 	if (!card) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err;
 	}
 	memset(card, 0, sizeof(avmcard));
         card->dma = avmcard_dma_alloc(driver->name, dev, 2048+128, 2048+128);
 	if (!card->dma) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err_kfree;
 	}
-        cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
+        cinfo = kmalloc(sizeof(avmctrl_info), GFP_KERNEL);
 	if (!cinfo) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-		avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err_dma_free;
 	}
 	memset(cinfo, 0, sizeof(avmctrl_info));
 	card->ctrlinfo = cinfo;
@@ -112,72 +85,50 @@
 	card->membase = p->membase;
 	card->cardtype = avm_t1pci;
 
-	if (check_region(card->port, AVMB1_PORTLEN)) {
+	if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
 		printk(KERN_WARNING
 		       "%s: ports 0x%03x-0x%03x in use.\n",
 		       driver->name, card->port, card->port + AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-		avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		retval = -EBUSY;
+		goto err_kfree_ctrlinfo;
 	}
 
 	card->mbase = ioremap_nocache(card->membase, 64);
 	if (!card->mbase) {
 		printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
 					driver->name, card->membase);
-	        kfree(card->ctrlinfo);
-		avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EIO;
+		retval = -EIO;
+		goto err_release_region;
 	}
 
 	b1dma_reset(card);
 
-	if ((retval = t1pci_detect(card)) != 0) {
+	retval = t1pci_detect(card);
+	if (retval != 0) {
 		if (retval < 6)
 			printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
 					driver->name, card->port, retval);
 		else
 			printk(KERN_NOTICE "%s: card at 0x%x, but cabel not connected or T1 has no power (%d)\n",
 					driver->name, card->port, retval);
-                iounmap(card->mbase);
-	        kfree(card->ctrlinfo);
-		avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EIO;
+		retval = -EIO;
+		goto err_unmap;
 	}
 	b1dma_reset(card);
 
-	request_region(p->port, AVMB1_PORTLEN, card->name);
-
 	retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card);
 	if (retval) {
 		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
 				driver->name, card->irq);
-                iounmap(card->mbase);
-		release_region(card->port, AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-		avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		retval = -EBUSY;
+		goto err_unmap;
 	}
 
 	cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
 	if (!cinfo->capi_ctrl) {
 		printk(KERN_ERR "%s: attach controller failed.\n", driver->name);
-                iounmap(card->mbase);
-		free_irq(card->irq, card);
-		release_region(card->port, AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-		avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		retval = -EBUSY;
+		goto err_free_irq;
 	}
 	card->cardnr = cinfo->capi_ctrl->cnr;
 
@@ -186,6 +137,43 @@
 		driver->name, card->port, card->irq, card->membase);
 
 	return 0;
+
+ err_free_irq:
+	free_irq(card->irq, card);
+ err_unmap:
+	iounmap(card->mbase);
+ err_release_region:
+	release_region(card->port, AVMB1_PORTLEN);
+ err_kfree_ctrlinfo:
+	kfree(card->ctrlinfo);
+ err_dma_free:
+	avmcard_dma_free(card->dma);
+ err_kfree:
+	kfree(card);
+ err:
+	MOD_DEC_USE_COUNT;
+	return retval;
+}
+
+/* ------------------------------------------------------------- */
+
+static void t1pci_remove_ctr(struct capi_ctr *ctrl)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
+
+ 	b1dma_reset(card);
+
+	di->detach_ctr(ctrl);
+	free_irq(card->irq, card);
+	iounmap(card->mbase);
+	release_region(card->port, AVMB1_PORTLEN);
+	ctrl->driverdata = 0;
+	kfree(card->ctrlinfo);
+	avmcard_dma_free(card->dma);
+	kfree(card);
+
+	MOD_DEC_USE_COUNT;
 }
 
 /* ------------------------------------------------------------- */
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c
--- v2.5.2/linux/drivers/isdn/isdn_common.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/isdn/isdn_common.c	Thu Jan 17 14:04:15 2002
@@ -65,7 +65,6 @@
 #endif /* CONFIG_ISDN_DIVERSION */
 
 
-static int isdn_writebuf_stub(int, int, const u_char *, int, int);
 static void set_global_features(void);
 static void isdn_register_devfs(int);
 static void isdn_unregister_devfs(int);
@@ -946,7 +945,9 @@
 	return istatbuf;
 }
 
-/* Module interface-code */
+/* 
+ * /dev/isdninfo
+ */
 
 void
 isdn_info_update(void)
@@ -960,234 +961,309 @@
 	wake_up_interruptible(&(dev->info_waitq));
 }
 
+static int
+isdn_status_open(struct inode *ino, struct file *filep)
+{
+	infostruct *p;
+	
+	p = kmalloc(sizeof(infostruct), GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+
+	p->next = (char *) dev->infochain;
+	p->private = (char *) &(filep->private_data);
+	dev->infochain = p;
+	/* At opening we allow a single update */
+	filep->private_data = (char *) 1;
+
+	return 0;
+}
+
+static int
+isdn_status_release(struct inode *ino, struct file *filep)
+{
+	infostruct *p = dev->infochain;
+	infostruct *q = NULL;
+	
+	lock_kernel();
+
+	while (p) {
+		if (p->private == (char *) &(filep->private_data)) {
+			if (q)
+				q->next = p->next;
+			else
+				dev->infochain = (infostruct *) (p->next);
+			kfree(p);
+			goto out;
+		}
+		q = p;
+		p = (infostruct *) (p->next);
+	}
+	printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
+
+ out:
+	unlock_kernel();
+	return 0;
+}
+
 static ssize_t
-isdn_read(struct file *file, char *buf, size_t count, loff_t * off)
+isdn_status_read(struct file *file, char *buf, size_t count, loff_t * off)
 {
-	uint minor = minor(file->f_dentry->d_inode->i_rdev);
-	int len = 0;
-	ulong flags;
-	int drvidx;
-	int chidx;
 	int retval;
+	int len = 0;
 	char *p;
 
 	if (off != &file->f_pos)
 		return -ESPIPE;
 
 	lock_kernel();
-	if (minor == ISDN_MINOR_STATUS) {
-		if (!file->private_data) {
-			if (file->f_flags & O_NONBLOCK) {
-				retval = -EAGAIN;
-				goto out;
-			}
-			interruptible_sleep_on(&(dev->info_waitq));
-		}
-		p = isdn_statstr();
-		file->private_data = 0;
-		if ((len = strlen(p)) <= count) {
-			if (copy_to_user(buf, p, len)) {
-				retval = -EFAULT;
-				goto out;
-			}
-			*off += len;
-			retval = len;
+	if (!file->private_data) {
+		if (file->f_flags & O_NONBLOCK) {
+			retval = -EAGAIN;
 			goto out;
 		}
-		retval = 0;
-		goto out;
-	}
-	if (!dev->drivers) {
-		retval = -ENODEV;
-		goto out;
+		interruptible_sleep_on(&(dev->info_waitq));
 	}
-	if (minor <= ISDN_MINOR_BMAX) {
-		printk(KERN_WARNING "isdn_read minor %d obsolete!\n", minor);
-		drvidx = isdn_minor2drv(minor);
-		if (drvidx < 0) {
-			retval = -ENODEV;
-			goto out;
-		}
-		if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) {
-			retval = -ENODEV;
+	p = isdn_statstr();
+	file->private_data = 0;
+	if ((len = strlen(p)) <= count) {
+		if (copy_to_user(buf, p, len)) {
+			retval = -EFAULT;
 			goto out;
 		}
-		chidx = isdn_minor2chan(minor);
-		if (!(p = kmalloc(count, GFP_KERNEL))) {
-			retval = -ENOMEM;
-			goto out;
-		}
-		save_flags(flags);
-		cli();
-		len = isdn_readbchan(drvidx, chidx, p, 0, count,
-				     &dev->drv[drvidx]->rcv_waitq[chidx]);
-		*off += len;
-		restore_flags(flags);
-		if (copy_to_user(buf,p,len)) 
-			len = -EFAULT;
-		kfree(p);
-		retval = len;
-		goto out;
-	}
-	if (minor <= ISDN_MINOR_CTRLMAX) {
-		drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
-		if (drvidx < 0) {
-			retval = -ENODEV;
-			goto out;
-		}
-		if (!dev->drv[drvidx]->stavail) {
-			if (file->f_flags & O_NONBLOCK) {
-				retval = -EAGAIN;
-				goto out;
-			}
-			interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq));
-		}
-		if (dev->drv[drvidx]->interface->readstat) {
-			if (count > dev->drv[drvidx]->stavail)
-				count = dev->drv[drvidx]->stavail;
-			len = dev->drv[drvidx]->interface->
-				readstat(buf, count, 1, drvidx,
-					 isdn_minor2chan(minor));
-		} else {
-			len = 0;
-		}
-		save_flags(flags);
-		cli();
-		if (len)
-			dev->drv[drvidx]->stavail -= len;
-		else
-			dev->drv[drvidx]->stavail = 0;
-		restore_flags(flags);
 		*off += len;
 		retval = len;
 		goto out;
 	}
-#ifdef CONFIG_ISDN_PPP
-	if (minor <= ISDN_MINOR_PPPMAX) {
-		retval = isdn_ppp_read(minor - ISDN_MINOR_PPP, file, buf, count);
-		goto out;
-	}
-#endif
-	retval = -ENODEV;
+	retval = 0;
+	goto out;
+
  out:
 	unlock_kernel();
 	return retval;
 }
 
 static ssize_t
-isdn_write(struct file *file, const char *buf, size_t count, loff_t * off)
+isdn_status_write(struct file *file, const char *buf, size_t count, loff_t *off)
+{
+	return -EPERM;
+}
+
+static unsigned int
+isdn_status_poll(struct file *file, poll_table *wait)
+{
+	unsigned int mask = 0;
+
+	lock_kernel();
+
+	poll_wait(file, &(dev->info_waitq), wait);
+	if (file->private_data)
+		mask |= POLLIN | POLLRDNORM;
+
+	unlock_kernel();
+	return mask;
+}
+
+static int
+isdn_status_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+{
+	int ret;
+	union iocpar {
+		char name[10];
+		char bname[22];
+		isdn_ioctl_struct iocts;
+		isdn_net_ioctl_phone phone;
+		isdn_net_ioctl_cfg cfg;
+	} iocpar;
+
+#define name  iocpar.name
+#define bname iocpar.bname
+#define iocts iocpar.iocts
+#define phone iocpar.phone
+#define cfg   iocpar.cfg
+
+	switch (cmd) {
+	case IIOCGETDVR:
+		return (TTY_DV +
+			(NET_DV << 8) +
+			(INF_DV << 16));
+	case IIOCGETCPS:
+		if (arg) {
+			ulong *p = (ulong *) arg;
+			int i;
+			if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
+					       sizeof(ulong) * ISDN_MAX_CHANNELS * 2)))
+				return ret;
+			for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+				put_user(dev->ibytes[i], p++);
+				put_user(dev->obytes[i], p++);
+			}
+			return 0;
+		} else
+			return -EINVAL;
+		break;
+#ifdef CONFIG_NETDEVICES
+	case IIOCNETGPN:
+		/* Get peer phone number of a connected 
+		 * isdn network interface */
+		if (arg) {
+			if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
+				return -EFAULT;
+			return isdn_net_getpeer(&phone, (isdn_net_ioctl_phone *) arg);
+		} else
+			return -EINVAL;
+#endif
+	default:
+		return -EINVAL;
+	}
+
+#undef name
+#undef bname
+#undef iocts
+#undef phone
+#undef cfg
+}
+
+/*
+ * /dev/isdnctrlX
+ */
+
+static int
+isdn_ctrl_open(struct inode *ino, struct file *filep)
+{
+	uint minor = minor(ino->i_rdev);
+	int drvidx;
+
+	drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+	if (drvidx < 0)
+		return -ENODEV;
+
+	isdn_lock_drivers();
+	return 0;
+}
+
+static int
+isdn_ctrl_release(struct inode *ino, struct file *filep)
+{
+	lock_kernel();
+
+	if (dev->profd == current)
+		dev->profd = NULL;
+
+	isdn_unlock_drivers();
+
+	unlock_kernel();
+	return 0;
+}
+
+static ssize_t
+isdn_ctrl_read(struct file *file, char *buf, size_t count, loff_t * off)
 {
 	uint minor = minor(file->f_dentry->d_inode->i_rdev);
+	ulong flags;
+	int len = 0;
 	int drvidx;
-	int chidx;
 	int retval;
 
 	if (off != &file->f_pos)
 		return -ESPIPE;
 
-	if (minor == ISDN_MINOR_STATUS)
-		return -EPERM;
-	if (!dev->drivers)
-		return -ENODEV;
-
 	lock_kernel();
-	if (minor <= ISDN_MINOR_BMAX) {
-		printk(KERN_WARNING "isdn_write minor %d obsolete!\n", minor);
-		drvidx = isdn_minor2drv(minor);
-		if (drvidx < 0) {
-			retval = -ENODEV;
-			goto out;
-		}
-		if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) {
-			retval = -ENODEV;
-			goto out;
-		}
-		chidx = isdn_minor2chan(minor);
-		while (isdn_writebuf_stub(drvidx, chidx, buf, count, 1) != count)
-			interruptible_sleep_on(&dev->drv[drvidx]->snd_waitq[chidx]);
-		retval = count;
+
+	drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+	if (drvidx < 0) {
+		retval = -ENODEV;
 		goto out;
 	}
-	if (minor <= ISDN_MINOR_CTRLMAX) {
-		drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
-		if (drvidx < 0) {
-			retval = -ENODEV;
+	if (!dev->drv[drvidx]->stavail) {
+		if (file->f_flags & O_NONBLOCK) {
+			retval = -EAGAIN;
 			goto out;
 		}
-		/*
-		 * We want to use the isdnctrl device to load the firmware
-		 *
-		 if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
-		 return -ENODEV;
-		 */
-		if (dev->drv[drvidx]->interface->writecmd)
-			retval = dev->drv[drvidx]->interface->
-				writecmd(buf, count, 1, drvidx, isdn_minor2chan(minor));
-		else
-			retval = count;
-		goto out;
+		interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq));
 	}
-#ifdef CONFIG_ISDN_PPP
-	if (minor <= ISDN_MINOR_PPPMAX) {
-		retval = isdn_ppp_write(minor - ISDN_MINOR_PPP, file, buf, count);
-		goto out;
+	if (dev->drv[drvidx]->interface->readstat) {
+		if (count > dev->drv[drvidx]->stavail)
+			count = dev->drv[drvidx]->stavail;
+		len = dev->drv[drvidx]->interface->
+			readstat(buf, count, 1, drvidx,
+				 isdn_minor2chan(minor));
+	} else {
+		len = 0;
 	}
-#endif
-	retval = -ENODEV;
+	save_flags(flags);
+	cli();
+	if (len)
+		dev->drv[drvidx]->stavail -= len;
+	else
+		dev->drv[drvidx]->stavail = 0;
+	restore_flags(flags);
+	*off += len;
+	retval = len;
+	
  out:
 	unlock_kernel();
 	return retval;
 }
 
-static unsigned int
-isdn_poll(struct file *file, poll_table * wait)
+static ssize_t
+isdn_ctrl_write(struct file *file, const char *buf, size_t count, loff_t *off)
 {
-	unsigned int mask = 0;
-	unsigned int minor = minor(file->f_dentry->d_inode->i_rdev);
-	int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+	uint minor = minor(file->f_dentry->d_inode->i_rdev);
+	int drvidx;
+	int retval;
+
+	if (off != &file->f_pos)
+		return -ESPIPE;
 
 	lock_kernel();
-	if (minor == ISDN_MINOR_STATUS) {
-		poll_wait(file, &(dev->info_waitq), wait);
-		/* mask = POLLOUT | POLLWRNORM; */
-		if (file->private_data) {
-			mask |= POLLIN | POLLRDNORM;
-		}
-		goto out;
-	}
-	if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) {
-		if (drvidx < 0) {
-			/* driver deregistered while file open */
-			mask = POLLHUP;
-			goto out;
-		}
-		poll_wait(file, &(dev->drv[drvidx]->st_waitq), wait);
-		mask = POLLOUT | POLLWRNORM;
-		if (dev->drv[drvidx]->stavail) {
-			mask |= POLLIN | POLLRDNORM;
-		}
+
+	drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+	if (drvidx < 0) {
+		retval = -ENODEV;
 		goto out;
 	}
-#ifdef CONFIG_ISDN_PPP
-	if (minor <= ISDN_MINOR_PPPMAX) {
-		mask = isdn_ppp_poll(file, wait);
+	if (!dev->drv[drvidx]->interface->writecmd) {
+		retval = -EINVAL;
 		goto out;
 	}
-#endif
-	mask = POLLERR;
+	retval = dev->drv[drvidx]->interface->
+		writecmd(buf, count, 1, drvidx, isdn_minor2chan(minor - ISDN_MINOR_CTRL));
+
  out:
 	unlock_kernel();
+	return retval;
+}
+
+static unsigned int
+isdn_ctrl_poll(struct file *file, poll_table *wait)
+{
+	unsigned int mask = 0;
+	unsigned int minor = minor(file->f_dentry->d_inode->i_rdev);
+	int drvidx;
+
+	drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+	if (drvidx < 0)
+		/* driver deregistered while file open */
+		return POLLHUP;
+
+	lock_kernel();
+
+	poll_wait(file, &(dev->drv[drvidx]->st_waitq), wait);
+	mask = POLLOUT | POLLWRNORM;
+	if (dev->drv[drvidx]->stavail)
+		mask |= POLLIN | POLLRDNORM;
+
+	unlock_kernel();
 	return mask;
 }
 
 
 static int
-isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+isdn_ctrl_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
 {
-	uint minor = minor(inode->i_rdev);
 	isdn_ctrl c;
 	int drvidx;
-	int chidx;
 	int ret;
 	int i;
 	char *p;
@@ -1205,55 +1281,6 @@
 #define iocts iocpar.iocts
 #define phone iocpar.phone
 #define cfg   iocpar.cfg
-
-	if (minor == ISDN_MINOR_STATUS) {
-		switch (cmd) {
-			case IIOCGETDVR:
-				return (TTY_DV +
-					(NET_DV << 8) +
-					(INF_DV << 16));
-			case IIOCGETCPS:
-				if (arg) {
-					ulong *p = (ulong *) arg;
-					int i;
-					if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
-							       sizeof(ulong) * ISDN_MAX_CHANNELS * 2)))
-						return ret;
-					for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-						put_user(dev->ibytes[i], p++);
-						put_user(dev->obytes[i], p++);
-					}
-					return 0;
-				} else
-					return -EINVAL;
-				break;
-#ifdef CONFIG_NETDEVICES
-			case IIOCNETGPN:
-				/* Get peer phone number of a connected 
-				 * isdn network interface */
-				if (arg) {
-					if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
-						return -EFAULT;
-					return isdn_net_getpeer(&phone, (isdn_net_ioctl_phone *) arg);
-				} else
-					return -EINVAL;
-#endif
-			default:
-				return -EINVAL;
-		}
-	}
-	if (!dev->drivers)
-		return -ENODEV;
-	if (minor <= ISDN_MINOR_BMAX) {
-		drvidx = isdn_minor2drv(minor);
-		if (drvidx < 0)
-			return -ENODEV;
-		chidx = isdn_minor2chan(minor);
-		if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
-			return -ENODEV;
-		return 0;
-	}
-	if (minor <= ISDN_MINOR_CTRLMAX) {
 /*
  * isdn net devices manage lots of configuration variables as linked lists.
  * Those lists must only be manipulated from user space. Some of the ioctl's
@@ -1261,366 +1288,360 @@
  * manipulating the lists and ioctl's sleeping while accessing the lists
  * are serialized by means of a semaphore.
  */
-		switch (cmd) {
-			case IIOCNETDWRSET:
-				printk(KERN_INFO "INFO: ISDN_DW_ABC_EXTENSION not enabled\n");
-				return(-EINVAL);
-			case IIOCNETLCR:
-				printk(KERN_INFO "INFO: ISDN_ABC_LCR_SUPPORT not enabled\n");
-				return -ENODEV;
+	switch (cmd) {
+	case IIOCNETDWRSET:
+		printk(KERN_INFO "INFO: ISDN_DW_ABC_EXTENSION not enabled\n");
+		return(-EINVAL);
+	case IIOCNETLCR:
+		printk(KERN_INFO "INFO: ISDN_ABC_LCR_SUPPORT not enabled\n");
+		return -ENODEV;
 #ifdef CONFIG_NETDEVICES
-			case IIOCNETAIF:
-				/* Add a network-interface */
-				if (arg) {
-					if (copy_from_user(name, (char *) arg, sizeof(name)))
-						return -EFAULT;
-					s = name;
-				} else {
-					s = NULL;
-				}
-				ret = down_interruptible(&dev->sem);
-				if( ret ) return ret;
-				if ((s = isdn_net_new(s, NULL))) {
-					if (copy_to_user((char *) arg, s, strlen(s) + 1)){
-						ret = -EFAULT;
-					} else {
-						ret = 0;
+	case IIOCNETAIF:
+		/* Add a network-interface */
+		if (arg) {
+			if (copy_from_user(name, (char *) arg, sizeof(name)))
+				return -EFAULT;
+			s = name;
+		} else {
+			s = NULL;
+		}
+		ret = down_interruptible(&dev->sem);
+		if( ret ) return ret;
+		if ((s = isdn_net_new(s, NULL))) {
+			if (copy_to_user((char *) arg, s, strlen(s) + 1)){
+				ret = -EFAULT;
+			} else {
+				ret = 0;
+			}
+		} else
+			ret = -ENODEV;
+		up(&dev->sem);
+		return ret;
+	case IIOCNETASL:
+		/* Add a slave to a network-interface */
+		if (arg) {
+			if (copy_from_user(bname, (char *) arg, sizeof(bname) - 1))
+				return -EFAULT;
+		} else
+			return -EINVAL;
+		ret = down_interruptible(&dev->sem);
+		if( ret ) return ret;
+		if ((s = isdn_net_newslave(bname))) {
+			if (copy_to_user((char *) arg, s, strlen(s) + 1)){
+				ret = -EFAULT;
+			} else {
+				ret = 0;
+			}
+		} else
+			ret = -ENODEV;
+		up(&dev->sem);
+		return ret;
+	case IIOCNETDIF:
+		/* Delete a network-interface */
+		if (arg) {
+			if (copy_from_user(name, (char *) arg, sizeof(name)))
+				return -EFAULT;
+			ret = down_interruptible(&dev->sem);
+			if( ret ) return ret;
+			ret = isdn_net_rm(name);
+			up(&dev->sem);
+			return ret;
+		} else
+			return -EINVAL;
+	case IIOCNETSCF:
+		/* Set configurable parameters of a network-interface */
+		if (arg) {
+			if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg)))
+				return -EFAULT;
+			return isdn_net_setcfg(&cfg);
+		} else
+			return -EINVAL;
+	case IIOCNETGCF:
+		/* Get configurable parameters of a network-interface */
+		if (arg) {
+			if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg)))
+				return -EFAULT;
+			if (!(ret = isdn_net_getcfg(&cfg))) {
+				if (copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg)))
+					return -EFAULT;
+			}
+			return ret;
+		} else
+			return -EINVAL;
+	case IIOCNETANM:
+		/* Add a phone-number to a network-interface */
+		if (arg) {
+			if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
+				return -EFAULT;
+			ret = down_interruptible(&dev->sem);
+			if( ret ) return ret;
+			ret = isdn_net_addphone(&phone);
+			up(&dev->sem);
+			return ret;
+		} else
+			return -EINVAL;
+	case IIOCNETGNM:
+		/* Get list of phone-numbers of a network-interface */
+		if (arg) {
+			if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
+				return -EFAULT;
+			ret = down_interruptible(&dev->sem);
+			if( ret ) return ret;
+			ret = isdn_net_getphones(&phone, (char *) arg);
+			up(&dev->sem);
+			return ret;
+		} else
+			return -EINVAL;
+	case IIOCNETDNM:
+		/* Delete a phone-number of a network-interface */
+		if (arg) {
+			if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
+				return -EFAULT;
+			ret = down_interruptible(&dev->sem);
+			if( ret ) return ret;
+			ret = isdn_net_delphone(&phone);
+			up(&dev->sem);
+			return ret;
+		} else
+			return -EINVAL;
+	case IIOCNETDIL:
+		/* Force dialing of a network-interface */
+		if (arg) {
+			if (copy_from_user(name, (char *) arg, sizeof(name)))
+				return -EFAULT;
+			return isdn_net_force_dial(name);
+		} else
+			return -EINVAL;
+#ifdef CONFIG_ISDN_PPP
+	case IIOCNETALN:
+		if (!arg)
+			return -EINVAL;
+		if (copy_from_user(name, (char *) arg, sizeof(name)))
+			return -EFAULT;
+		return isdn_ppp_dial_slave(name);
+	case IIOCNETDLN:
+		if (!arg)
+			return -EINVAL;
+		if (copy_from_user(name, (char *) arg, sizeof(name)))
+			return -EFAULT;
+		return isdn_ppp_hangup_slave(name);
+#endif
+	case IIOCNETHUP:
+		/* Force hangup of a network-interface */
+		if (!arg)
+			return -EINVAL;
+		if (copy_from_user(name, (char *) arg, sizeof(name)))
+			return -EFAULT;
+		return isdn_net_force_hangup(name);
+		break;
+#endif                          /* CONFIG_NETDEVICES */
+	case IIOCSETVER:
+		dev->net_verbose = arg;
+		printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose);
+		return 0;
+	case IIOCSETGST:
+		if (arg)
+			dev->global_flags |= ISDN_GLOBAL_STOPPED;
+		else
+			dev->global_flags &= ~ISDN_GLOBAL_STOPPED;
+		printk(KERN_INFO "isdn: Global Mode %s\n",
+		       (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running");
+		return 0;
+	case IIOCSETBRJ:
+		drvidx = -1;
+		if (arg) {
+			int i;
+			char *p;
+			if (copy_from_user((char *) &iocts, (char *) arg,
+					   sizeof(isdn_ioctl_struct)))
+				return -EFAULT;
+			if (strlen(iocts.drvid)) {
+				if ((p = strchr(iocts.drvid, ',')))
+					*p = 0;
+				drvidx = -1;
+				for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+					if (!(strcmp(dev->drvid[i], iocts.drvid))) {
+						drvidx = i;
+						break;
 					}
-				} else
-					ret = -ENODEV;
-				up(&dev->sem);
+			}
+		}
+		if (drvidx == -1)
+			return -ENODEV;
+		if (iocts.arg)
+			dev->drv[drvidx]->flags |= DRV_FLAG_REJBUS;
+		else
+			dev->drv[drvidx]->flags &= ~DRV_FLAG_REJBUS;
+		return 0;
+	case IIOCSIGPRF:
+		dev->profd = current;
+		return 0;
+		break;
+	case IIOCGETPRF:
+		/* Get all Modem-Profiles */
+		if (arg) {
+			char *p = (char *) arg;
+			int i;
+
+			if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
+					       (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN)
+					       * ISDN_MAX_CHANNELS)))
 				return ret;
-			case IIOCNETASL:
-				/* Add a slave to a network-interface */
-				if (arg) {
-					if (copy_from_user(bname, (char *) arg, sizeof(bname) - 1))
-						return -EFAULT;
-				} else
-					return -EINVAL;
-				ret = down_interruptible(&dev->sem);
-				if( ret ) return ret;
-				if ((s = isdn_net_newslave(bname))) {
-					if (copy_to_user((char *) arg, s, strlen(s) + 1)){
-						ret = -EFAULT;
-					} else {
-						ret = 0;
-					}
-				} else
-					ret = -ENODEV;
-				up(&dev->sem);
+
+			for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+				if (copy_to_user(p, dev->mdm.info[i].emu.profile,
+						 ISDN_MODEM_NUMREG))
+					return -EFAULT;
+				p += ISDN_MODEM_NUMREG;
+				if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN))
+					return -EFAULT;
+				p += ISDN_MSNLEN;
+				if (copy_to_user(p, dev->mdm.info[i].emu.plmsn, ISDN_LMSNLEN))
+					return -EFAULT;
+				p += ISDN_LMSNLEN;
+			}
+			return (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS;
+		} else
+			return -EINVAL;
+		break;
+	case IIOCSETPRF:
+		/* Set all Modem-Profiles */
+		if (arg) {
+			char *p = (char *) arg;
+			int i;
+
+			if ((ret = verify_area(VERIFY_READ, (void *) arg,
+					       (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN)
+					       * ISDN_MAX_CHANNELS)))
 				return ret;
-			case IIOCNETDIF:
-				/* Delete a network-interface */
-				if (arg) {
-					if (copy_from_user(name, (char *) arg, sizeof(name)))
-						return -EFAULT;
-					ret = down_interruptible(&dev->sem);
-					if( ret ) return ret;
-					ret = isdn_net_rm(name);
-					up(&dev->sem);
-					return ret;
-				} else
-					return -EINVAL;
-			case IIOCNETSCF:
-				/* Set configurable parameters of a network-interface */
-				if (arg) {
-					if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg)))
-						return -EFAULT;
-					return isdn_net_setcfg(&cfg);
-				} else
-					return -EINVAL;
-			case IIOCNETGCF:
-				/* Get configurable parameters of a network-interface */
-				if (arg) {
-					if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg)))
-						return -EFAULT;
-					if (!(ret = isdn_net_getcfg(&cfg))) {
-						if (copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg)))
-							return -EFAULT;
-					}
-					return ret;
-				} else
-					return -EINVAL;
-			case IIOCNETANM:
-				/* Add a phone-number to a network-interface */
-				if (arg) {
-					if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
-						return -EFAULT;
-					ret = down_interruptible(&dev->sem);
-					if( ret ) return ret;
-					ret = isdn_net_addphone(&phone);
-					up(&dev->sem);
-					return ret;
-				} else
-					return -EINVAL;
-			case IIOCNETGNM:
-				/* Get list of phone-numbers of a network-interface */
-				if (arg) {
-					if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
-						return -EFAULT;
-					ret = down_interruptible(&dev->sem);
-					if( ret ) return ret;
-					ret = isdn_net_getphones(&phone, (char *) arg);
-					up(&dev->sem);
-					return ret;
-				} else
-					return -EINVAL;
-			case IIOCNETDNM:
-				/* Delete a phone-number of a network-interface */
-				if (arg) {
-					if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
-						return -EFAULT;
-					ret = down_interruptible(&dev->sem);
-					if( ret ) return ret;
-					ret = isdn_net_delphone(&phone);
-					up(&dev->sem);
-					return ret;
-				} else
-					return -EINVAL;
-			case IIOCNETDIL:
-				/* Force dialing of a network-interface */
-				if (arg) {
-					if (copy_from_user(name, (char *) arg, sizeof(name)))
-						return -EFAULT;
-					return isdn_net_force_dial(name);
-				} else
-					return -EINVAL;
-#ifdef CONFIG_ISDN_PPP
-			case IIOCNETALN:
-				if (!arg)
-					return -EINVAL;
-				if (copy_from_user(name, (char *) arg, sizeof(name)))
+
+			for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+				if (copy_from_user(dev->mdm.info[i].emu.profile, p,
+						   ISDN_MODEM_NUMREG))
 					return -EFAULT;
-				return isdn_ppp_dial_slave(name);
-			case IIOCNETDLN:
-				if (!arg)
-					return -EINVAL;
-				if (copy_from_user(name, (char *) arg, sizeof(name)))
+				p += ISDN_MODEM_NUMREG;
+				if (copy_from_user(dev->mdm.info[i].emu.plmsn, p, ISDN_LMSNLEN))
 					return -EFAULT;
-				return isdn_ppp_hangup_slave(name);
-#endif
-			case IIOCNETHUP:
-				/* Force hangup of a network-interface */
-				if (!arg)
-					return -EINVAL;
-				if (copy_from_user(name, (char *) arg, sizeof(name)))
+				p += ISDN_LMSNLEN;
+				if (copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN))
 					return -EFAULT;
-				return isdn_net_force_hangup(name);
-				break;
-#endif                          /* CONFIG_NETDEVICES */
-			case IIOCSETVER:
-				dev->net_verbose = arg;
-				printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose);
-				return 0;
-			case IIOCSETGST:
-				if (arg)
-					dev->global_flags |= ISDN_GLOBAL_STOPPED;
-				else
-					dev->global_flags &= ~ISDN_GLOBAL_STOPPED;
-				printk(KERN_INFO "isdn: Global Mode %s\n",
-				       (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running");
-				return 0;
-			case IIOCSETBRJ:
+				p += ISDN_MSNLEN;
+			}
+			return 0;
+		} else
+			return -EINVAL;
+		break;
+	case IIOCSETMAP:
+	case IIOCGETMAP:
+		/* Set/Get MSN->EAZ-Mapping for a driver */
+		if (arg) {
+
+			if (copy_from_user((char *) &iocts,
+					   (char *) arg,
+					   sizeof(isdn_ioctl_struct)))
+				return -EFAULT;
+			if (strlen(iocts.drvid)) {
 				drvidx = -1;
-				if (arg) {
-					int i;
-					char *p;
-					if (copy_from_user((char *) &iocts, (char *) arg,
-					     sizeof(isdn_ioctl_struct)))
-						return -EFAULT;
-					if (strlen(iocts.drvid)) {
-						if ((p = strchr(iocts.drvid, ',')))
-							*p = 0;
-						drvidx = -1;
-						for (i = 0; i < ISDN_MAX_DRIVERS; i++)
-							if (!(strcmp(dev->drvid[i], iocts.drvid))) {
-								drvidx = i;
-								break;
-							}
-					}
-				}
-				if (drvidx == -1)
-					return -ENODEV;
-				if (iocts.arg)
-					dev->drv[drvidx]->flags |= DRV_FLAG_REJBUS;
-				else
-					dev->drv[drvidx]->flags &= ~DRV_FLAG_REJBUS;
-				return 0;
-			case IIOCSIGPRF:
-				dev->profd = current;
-				return 0;
-				break;
-			case IIOCGETPRF:
-				/* Get all Modem-Profiles */
-				if (arg) {
-					char *p = (char *) arg;
-					int i;
-
-					if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
-					(ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN)
-						   * ISDN_MAX_CHANNELS)))
-						return ret;
-
-					for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-						if (copy_to_user(p, dev->mdm.info[i].emu.profile,
-						      ISDN_MODEM_NUMREG))
-							return -EFAULT;
-						p += ISDN_MODEM_NUMREG;
-						if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN))
-							return -EFAULT;
-						p += ISDN_MSNLEN;
-						if (copy_to_user(p, dev->mdm.info[i].emu.plmsn, ISDN_LMSNLEN))
-							return -EFAULT;
-						p += ISDN_LMSNLEN;
-					}
-					return (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS;
-				} else
-					return -EINVAL;
-				break;
-			case IIOCSETPRF:
-				/* Set all Modem-Profiles */
-				if (arg) {
-					char *p = (char *) arg;
-					int i;
-
-					if ((ret = verify_area(VERIFY_READ, (void *) arg,
-					(ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN)
-						   * ISDN_MAX_CHANNELS)))
-						return ret;
-
-					for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-						if (copy_from_user(dev->mdm.info[i].emu.profile, p,
-						     ISDN_MODEM_NUMREG))
-							return -EFAULT;
-						p += ISDN_MODEM_NUMREG;
-						if (copy_from_user(dev->mdm.info[i].emu.plmsn, p, ISDN_LMSNLEN))
-							return -EFAULT;
-						p += ISDN_LMSNLEN;
-						if (copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN))
-							return -EFAULT;
-						p += ISDN_MSNLEN;
+				for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+					if (!(strcmp(dev->drvid[i], iocts.drvid))) {
+						drvidx = i;
+						break;
 					}
-					return 0;
-				} else
-					return -EINVAL;
-				break;
-			case IIOCSETMAP:
-			case IIOCGETMAP:
-				/* Set/Get MSN->EAZ-Mapping for a driver */
-				if (arg) {
-
-					if (copy_from_user((char *) &iocts,
-							    (char *) arg,
-					     sizeof(isdn_ioctl_struct)))
-						return -EFAULT;
-					if (strlen(iocts.drvid)) {
-						drvidx = -1;
-						for (i = 0; i < ISDN_MAX_DRIVERS; i++)
-							if (!(strcmp(dev->drvid[i], iocts.drvid))) {
-								drvidx = i;
-								break;
-							}
-					} else
-						drvidx = 0;
-					if (drvidx == -1)
-						return -ENODEV;
-					if (cmd == IIOCSETMAP) {
-						int loop = 1;
-
-						p = (char *) iocts.arg;
-						i = 0;
-						while (loop) {
-							int j = 0;
-
-							while (1) {
-								if ((ret = verify_area(VERIFY_READ, p, 1)))
-									return ret;
-								get_user(bname[j], p++);
-								switch (bname[j]) {
-									case '\0':
-										loop = 0;
-										/* Fall through */
-									case ',':
-										bname[j] = '\0';
-										strcpy(dev->drv[drvidx]->msn2eaz[i], bname);
-										j = ISDN_MSNLEN;
-										break;
-									default:
-										j++;
-								}
-								if (j >= ISDN_MSNLEN)
-									break;
-							}
-							if (++i > 9)
-								break;
-						}
-					} else {
-						p = (char *) iocts.arg;
-						for (i = 0; i < 10; i++) {
-							sprintf(bname, "%s%s",
-								strlen(dev->drv[drvidx]->msn2eaz[i]) ?
-								dev->drv[drvidx]->msn2eaz[i] : "_",
-								(i < 9) ? "," : "\0");
-							if (copy_to_user(p, bname, strlen(bname) + 1))
-								return -EFAULT;
-							p += strlen(bname);
+			} else
+				drvidx = 0;
+			if (drvidx == -1)
+				return -ENODEV;
+			if (cmd == IIOCSETMAP) {
+				int loop = 1;
+
+				p = (char *) iocts.arg;
+				i = 0;
+				while (loop) {
+					int j = 0;
+
+					while (1) {
+						if ((ret = verify_area(VERIFY_READ, p, 1)))
+							return ret;
+						get_user(bname[j], p++);
+						switch (bname[j]) {
+						case '\0':
+							loop = 0;
+							/* Fall through */
+						case ',':
+							bname[j] = '\0';
+							strcpy(dev->drv[drvidx]->msn2eaz[i], bname);
+							j = ISDN_MSNLEN;
+							break;
+						default:
+							j++;
 						}
+						if (j >= ISDN_MSNLEN)
+							break;
 					}
-					return 0;
-				} else
-					return -EINVAL;
-			case IIOCDBGVAR:
-				if (arg) {
-					if (copy_to_user((char *) arg, (char *) &dev, sizeof(ulong)))
-						return -EFAULT;
-					return 0;
-				} else
-					return -EINVAL;
-				break;
-			default:
-				if ((cmd & IIOCDRVCTL) == IIOCDRVCTL)
-					cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK;
-				else
-					return -EINVAL;
-				if (arg) {
-					int i;
-					char *p;
-					if (copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct)))
-						return -EFAULT;
-					if (strlen(iocts.drvid)) {
-						if ((p = strchr(iocts.drvid, ',')))
-							*p = 0;
-						drvidx = -1;
-						for (i = 0; i < ISDN_MAX_DRIVERS; i++)
-							if (!(strcmp(dev->drvid[i], iocts.drvid))) {
-								drvidx = i;
-								break;
-							}
-					} else
-						drvidx = 0;
-					if (drvidx == -1)
-						return -ENODEV;
-					if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
-					     sizeof(isdn_ioctl_struct))))
-						return ret;
-					c.driver = drvidx;
-					c.command = ISDN_CMD_IOCTL;
-					c.arg = cmd;
-					memcpy(c.parm.num, (char *) &iocts.arg, sizeof(ulong));
-					ret = isdn_command(&c);
-					memcpy((char *) &iocts.arg, c.parm.num, sizeof(ulong));
-					if (copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct)))
+					if (++i > 9)
+						break;
+				}
+			} else {
+				p = (char *) iocts.arg;
+				for (i = 0; i < 10; i++) {
+					sprintf(bname, "%s%s",
+						strlen(dev->drv[drvidx]->msn2eaz[i]) ?
+						dev->drv[drvidx]->msn2eaz[i] : "_",
+						(i < 9) ? "," : "\0");
+					if (copy_to_user(p, bname, strlen(bname) + 1))
 						return -EFAULT;
-					return ret;
-				} else
-					return -EINVAL;
-		}
+					p += strlen(bname);
+				}
+			}
+			return 0;
+		} else
+			return -EINVAL;
+	case IIOCDBGVAR:
+		if (arg) {
+			if (copy_to_user((char *) arg, (char *) &dev, sizeof(ulong)))
+				return -EFAULT;
+			return 0;
+		} else
+			return -EINVAL;
+		break;
+	default:
+		if ((cmd & IIOCDRVCTL) == IIOCDRVCTL)
+			cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK;
+		else
+			return -EINVAL;
+		if (arg) {
+			int i;
+			char *p;
+			if (copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct)))
+				return -EFAULT;
+			if (strlen(iocts.drvid)) {
+				if ((p = strchr(iocts.drvid, ',')))
+					*p = 0;
+				drvidx = -1;
+				for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+					if (!(strcmp(dev->drvid[i], iocts.drvid))) {
+						drvidx = i;
+						break;
+					}
+			} else
+				drvidx = 0;
+			if (drvidx == -1)
+				return -ENODEV;
+			if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
+					       sizeof(isdn_ioctl_struct))))
+				return ret;
+			c.driver = drvidx;
+			c.command = ISDN_CMD_IOCTL;
+			c.arg = cmd;
+			memcpy(c.parm.num, (char *) &iocts.arg, sizeof(ulong));
+			ret = isdn_command(&c);
+			memcpy((char *) &iocts.arg, c.parm.num, sizeof(ulong));
+			if (copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct)))
+				return -EFAULT;
+			return ret;
+		} else
+			return -EINVAL;
 	}
-#ifdef CONFIG_ISDN_PPP
-	if (minor <= ISDN_MINOR_PPPMAX)
-		return (isdn_ppp_ioctl(minor - ISDN_MINOR_PPP, file, cmd, arg));
-#endif
-	return -ENODEV;
 
 #undef name
 #undef bname
@@ -1630,67 +1651,120 @@
 }
 
 /*
+ *
+ */
+
+static ssize_t
+isdn_read(struct file *file, char *buf, size_t count, loff_t * off)
+{
+	uint minor = minor(file->f_dentry->d_inode->i_rdev);
+
+	if (minor < ISDN_MINOR_CTRL)
+		return -ENODEV;
+	
+	if (minor <= ISDN_MINOR_CTRLMAX)
+		return isdn_ctrl_read(file, buf, count, off);
+
+#ifdef CONFIG_ISDN_PPP
+	if (minor <= ISDN_MINOR_PPPMAX)
+		return isdn_ppp_read(file, buf, count, off);
+#endif
+
+	if (minor == ISDN_MINOR_STATUS)
+		return isdn_status_read(file, buf, count, off);
+
+	return -ENODEV;
+}
+
+static ssize_t
+isdn_write(struct file *file, const char *buf, size_t count, loff_t * off)
+{
+	uint minor = minor(file->f_dentry->d_inode->i_rdev);
+
+	if (minor < ISDN_MINOR_CTRL)
+		return -ENODEV;
+
+	if (minor <= ISDN_MINOR_CTRLMAX)
+		return isdn_ctrl_write(file, buf, count, off);
+
+#ifdef CONFIG_ISDN_PPP
+	if (minor <= ISDN_MINOR_PPPMAX)
+		return isdn_ppp_write(file, buf, count, off);
+#endif
+
+	if (minor == ISDN_MINOR_STATUS)
+		return isdn_status_write(file, buf, count, off);
+
+	return -ENODEV;
+}
+
+static unsigned int
+isdn_poll(struct file *file, poll_table * wait)
+{
+	unsigned int minor = minor(file->f_dentry->d_inode->i_rdev);
+
+	if (minor < ISDN_MINOR_CTRL)
+		return POLLERR;
+
+	if (minor <= ISDN_MINOR_CTRLMAX)
+		return isdn_ctrl_poll(file, wait);
+
+#ifdef CONFIG_ISDN_PPP
+	if (minor <= ISDN_MINOR_PPPMAX)
+		return isdn_ppp_poll(file, wait);
+#endif
+
+	if (minor == ISDN_MINOR_STATUS)
+		return isdn_status_poll(file, wait);
+
+	return POLLERR;
+}
+
+static int
+isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+{
+	uint minor = minor(inode->i_rdev);
+
+	if (minor == ISDN_MINOR_STATUS)
+		return isdn_status_ioctl(inode, file, cmd, arg);
+
+	if (minor < ISDN_MINOR_CTRL)
+		return -ENODEV;
+
+	if (minor <= ISDN_MINOR_CTRLMAX)
+		return isdn_ctrl_ioctl(inode, file, cmd, arg);
+
+#ifdef CONFIG_ISDN_PPP
+	if (minor <= ISDN_MINOR_PPPMAX)
+		return isdn_ppp_ioctl(inode, file, cmd, arg);
+#endif
+
+	return -ENODEV;
+}
+
+/*
  * Open the device code.
  */
 static int
 isdn_open(struct inode *ino, struct file *filep)
 {
 	uint minor = minor(ino->i_rdev);
-	int drvidx;
-	int chidx;
-	int retval = -ENODEV;
 
+	if (minor < ISDN_MINOR_CTRL)
+		return -ENODEV;
 
-	if (minor == ISDN_MINOR_STATUS) {
-		infostruct *p;
+	if (minor <= ISDN_MINOR_CTRLMAX)
+		return isdn_ctrl_open(ino, filep);
+
+	if (minor == ISDN_MINOR_STATUS)
+		return isdn_status_open(ino, filep);
 
-		if ((p = kmalloc(sizeof(infostruct), GFP_KERNEL))) {
-			p->next = (char *) dev->infochain;
-			p->private = (char *) &(filep->private_data);
-			dev->infochain = p;
-			/* At opening we allow a single update */
-			filep->private_data = (char *) 1;
-			retval = 0;
-			goto out;
-		} else {
-			retval = -ENOMEM;
-			goto out;
-		}
-	}
-	if (!dev->channels)
-		goto out;
-	if (minor <= ISDN_MINOR_BMAX) {
-		printk(KERN_WARNING "isdn_open minor %d obsolete!\n", minor);
-		drvidx = isdn_minor2drv(minor);
-		if (drvidx < 0)
-			goto out;
-		chidx = isdn_minor2chan(minor);
-		if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
-			goto out;
-		if (!(dev->drv[drvidx]->online & (1 << chidx)))
-			goto out;
-		isdn_lock_drivers();
-		retval = 0;
-		goto out;
-	}
-	if (minor <= ISDN_MINOR_CTRLMAX) {
-		drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
-		if (drvidx < 0)
-			goto out;
-		isdn_lock_drivers();
-		retval = 0;
-		goto out;
-	}
 #ifdef CONFIG_ISDN_PPP
-	if (minor <= ISDN_MINOR_PPPMAX) {
-		retval = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep);
-		if (retval == 0)
-			isdn_lock_drivers();
-		goto out;
-	}
+	if (minor <= ISDN_MINOR_PPPMAX)
+		return isdn_ppp_open(ino, filep);
 #endif
- out:
-	return retval;
+
+	return -ENODEV;
 }
 
 static int
@@ -1698,42 +1772,21 @@
 {
 	uint minor = minor(ino->i_rdev);
 
-	lock_kernel();
-	if (minor == ISDN_MINOR_STATUS) {
-		infostruct *p = dev->infochain;
-		infostruct *q = NULL;
-
-		while (p) {
-			if (p->private == (char *) &(filep->private_data)) {
-				if (q)
-					q->next = p->next;
-				else
-					dev->infochain = (infostruct *) (p->next);
-				kfree(p);
-				goto out;
-			}
-			q = p;
-			p = (infostruct *) (p->next);
-		}
-		printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
-		goto out;
-	}
-	isdn_unlock_drivers();
-	if (minor <= ISDN_MINOR_BMAX)
-		goto out;
-	if (minor <= ISDN_MINOR_CTRLMAX) {
-		if (dev->profd == current)
-			dev->profd = NULL;
-		goto out;
-	}
+	if (minor == ISDN_MINOR_STATUS)
+		return isdn_status_release(ino, filep);
+
+	if (minor < ISDN_MINOR_CTRL)
+		return -ENODEV;
+
+	if (minor <= ISDN_MINOR_CTRLMAX)
+		return isdn_ctrl_release(ino, filep);
+
 #ifdef CONFIG_ISDN_PPP
 	if (minor <= ISDN_MINOR_PPPMAX)
-		isdn_ppp_release(minor - ISDN_MINOR_PPP, filep);
+		return isdn_ppp_release(ino, filep);
 #endif
 
- out:
-	unlock_kernel();
-	return 0;
+	return -ENODEV;
 }
 
 static struct file_operations isdn_fops =
@@ -1875,32 +1928,6 @@
 			return;
 		}
 	restore_flags(flags);
-}
-
-/*
- *  writebuf replacement for SKB_ABLE drivers
- */
-static int
-isdn_writebuf_stub(int drvidx, int chan, const u_char * buf, int len,
-		   int user)
-{
-	int ret;
-	int hl = dev->drv[drvidx]->interface->hl_hdrlen;
-	struct sk_buff *skb = alloc_skb(hl + len, GFP_ATOMIC);
-
-	if (!skb)
-		return 0;
-	skb_reserve(skb, hl);
-	if (user)
-		copy_from_user(skb_put(skb, len), buf, len);
-	else
-		memcpy(skb_put(skb, len), buf, len);
-	ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, 1, skb);
-	if (ret <= 0)
-		dev_kfree_skb(skb);
-	if (ret > 0)
-		dev->obytes[isdn_dc2minor(drvidx, chan)] += ret;
-	return ret;
 }
 
 /*
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/isdn_common.h linux/drivers/isdn/isdn_common.h
--- v2.5.2/linux/drivers/isdn/isdn_common.h	Sun Sep 30 12:26:06 2001
+++ linux/drivers/isdn/isdn_common.h	Thu Jan 17 14:04:15 2002
@@ -27,6 +27,8 @@
 /* Prototypes */
 extern void isdn_MOD_INC_USE_COUNT(void);
 extern void isdn_MOD_DEC_USE_COUNT(void);
+extern void isdn_lock_drivers(void);
+extern void isdn_unlock_drivers(void);
 extern void isdn_free_channel(int di, int ch, int usage);
 extern void isdn_all_eaz(int di, int ch);
 extern int isdn_command(isdn_ctrl *);
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c
--- v2.5.2/linux/drivers/isdn/isdn_ppp.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/isdn/isdn_ppp.c	Thu Jan 17 14:04:15 2002
@@ -11,6 +11,7 @@
 
 #include <linux/config.h>
 #include <linux/isdn.h>
+#include <linux/smp_lock.h>
 #include <linux/poll.h>
 #include <linux/ppp-comp.h>
 
@@ -269,21 +270,19 @@
  */
 
 int
-isdn_ppp_open(int min, struct file *file)
+isdn_ppp_open(struct inode *ino, struct file *file)
 {
+	uint minor = minor(ino->i_rdev) - ISDN_MINOR_PPP;
 	int slot;
 	struct ippp_struct *is;
 
-	if (min < 0 || min > ISDN_MAX_CHANNELS)
-		return -ENODEV;
-
 	slot = isdn_ppp_get_slot();
 	if (slot < 0) {
 		return -EBUSY;
 	}
 	is = file->private_data = ippp_table[slot];
 
-		printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, min, is->state);
+		printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, minor, is->state);
 
 	/* compression stuff */
 	is->link_compressor   = is->compressor = NULL;
@@ -306,7 +305,7 @@
 	init_waitqueue_head(&is->wq);
 	is->first = is->rq + NUM_RCV_BUFFS - 1;	/* receive queue */
 	is->last = is->rq;
-	is->minor = min;
+	is->minor = minor;
 #ifdef CONFIG_ISDN_PPP_VJ
 	/*
 	 * VJ header compression init
@@ -315,6 +314,7 @@
 #endif
 
 	is->state = IPPP_OPEN;
+	isdn_lock_drivers();
 
 	return 0;
 }
@@ -322,18 +322,19 @@
 /*
  * release ippp device
  */
-void
-isdn_ppp_release(int min, struct file *file)
+int
+isdn_ppp_release(struct inode *ino, struct file *file)
 {
+	uint minor = minor(ino->i_rdev) - ISDN_MINOR_PPP;
 	int i;
 	struct ippp_struct *is;
 
-	if (min < 0 || min >= ISDN_MAX_CHANNELS)
-		return;
+	lock_kernel();
+
 	is = file->private_data;
 
 	if (is->debug & 0x1)
-		printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", min, (long) is->lp);
+		printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", minor, (long) is->lp);
 
 	if (is->lp) {           /* a lp address says: this link is still up */
 		isdn_net_dev *p = is->lp->netdev;
@@ -381,6 +382,11 @@
 
 	/* this slot is ready for new connections */
 	is->state = 0;
+
+	isdn_unlock_drivers();
+	
+	unlock_kernel();
+	return 0;
 }
 
 /*
@@ -413,7 +419,7 @@
  * ippp device ioctl
  */
 int
-isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
+isdn_ppp_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	unsigned long val;
 	int r,i,j;
@@ -425,7 +431,7 @@
 	lp = is->lp;
 
 	if (is->debug & 0x1)
-		printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", min, cmd, is->state);
+		printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", is->minor, cmd, is->state);
 
 	if (!(is->state & IPPP_OPEN))
 		return -EINVAL;
@@ -438,7 +444,7 @@
 			if ((r = get_arg((void *) arg, &val, sizeof(val) )))
 				return r;
 			printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n",
-			       (int) min, (int) is->unit, (int) val);
+			       (int) is->minor, (int) is->unit, (int) val);
 			return isdn_ppp_bundle(is, val);
 #else
 			return -1;
@@ -582,6 +588,7 @@
 	unsigned long flags;
 	struct ippp_struct *is;
 
+	lock_kernel();
 	is = file->private_data;
 
 	if (is->debug & 0x2)
@@ -592,10 +599,13 @@
 	poll_wait(file, &is->wq, wait);
 
 	if (!(is->state & IPPP_OPEN)) {
-		if(is->state == IPPP_CLOSEWAIT)
-			return POLLHUP;
+		if(is->state == IPPP_CLOSEWAIT) {
+			mask = POLLHUP;
+			goto out;
+		}
 		printk(KERN_DEBUG "isdn_ppp: device not open\n");
-		return POLLERR;
+		mask = POLLERR;
+		goto out;
 	}
 	/* we're always ready to send .. */
 	mask = POLLOUT | POLLWRNORM;
@@ -612,6 +622,9 @@
 		mask |= POLLIN | POLLRDNORM;
 	}
 	restore_flags(flags);
+
+ out:
+	unlock_kernel();
 	return mask;
 }
 
@@ -678,21 +691,28 @@
  */
 
 int
-isdn_ppp_read(int min, struct file *file, char *buf, int count)
+isdn_ppp_read(struct file *file, char *buf, int count, loff_t *off)
 {
 	struct ippp_struct *is;
 	struct ippp_buf_queue *b;
-	int r;
 	unsigned long flags;
 	unsigned char *save_buf;
+	int retval;
 
-	is = file->private_data;
+	if (off != &file->f_pos)
+		return -ESPIPE;
+	
+	lock_kernel();
 
-	if (!(is->state & IPPP_OPEN))
-		return 0;
+	is = file->private_data;
 
-	if ((r = verify_area(VERIFY_WRITE, (void *) buf, count)))
-		return r;
+	if (!(is->state & IPPP_OPEN)) {
+		retval = 0;
+		goto out;
+	}
+	retval = verify_area(VERIFY_WRITE, (void *) buf, count);
+	if (retval)
+		goto out;
 
 	save_flags(flags);
 	cli();
@@ -701,7 +721,8 @@
 	save_buf = b->buf;
 	if (!save_buf) {
 		restore_flags(flags);
-		return -EAGAIN;
+		retval = -EAGAIN;
+		goto out;
 	}
 	if (b->len < count)
 		count = b->len;
@@ -713,7 +734,11 @@
 	copy_to_user(buf, save_buf, count);
 	kfree(save_buf);
 
-	return count;
+	retval = count;
+
+ out:
+	unlock_kernel();
+	return retval;
 }
 
 /*
@@ -721,17 +746,25 @@
  */
 
 int
-isdn_ppp_write(int min, struct file *file, const char *buf, int count)
+isdn_ppp_write(struct file *file, const char *buf, int count, loff_t *off)
 {
 	isdn_net_local *lp;
 	struct ippp_struct *is;
 	int proto;
 	unsigned char protobuf[4];
+	int retval;
+
+	if (off != &file->f_pos)
+		return -ESPIPE;
+
+	lock_kernel();
 
 	is = file->private_data;
 
-	if (!(is->state & IPPP_CONNECT))
-		return 0;
+	if (!(is->state & IPPP_CONNECT)) {
+		retval = 0;
+		goto out;
+	}
 
 	lp = is->lp;
 
@@ -744,15 +777,18 @@
 		 * Don't reset huptimer for
 		 * LCP packets. (Echo requests).
 		 */
-		if (copy_from_user(protobuf, buf, 4))
-			return -EFAULT;
+		if (copy_from_user(protobuf, buf, 4)) {
+			retval = -EFAULT;
+			goto out;
+		}
 		proto = PPP_PROTOCOL(protobuf);
 		if (proto != PPP_LCP)
 			lp->huptimer = 0;
 
-		if (lp->isdn_device < 0 || lp->isdn_channel < 0)
-			return 0;
-
+		if (lp->isdn_device < 0 || lp->isdn_channel < 0) {
+			retval = 0;
+			goto out;
+		}
 		if ((dev->drv[lp->isdn_device]->flags & DRV_FLAG_RUNNING) &&
 			lp->dialstate == 0 &&
 		    (lp->flags & ISDN_NET_CONNECTED)) {
@@ -767,13 +803,15 @@
 			skb = alloc_skb(hl+count, GFP_ATOMIC);
 			if (!skb) {
 				printk(KERN_WARNING "isdn_ppp_write: out of memory!\n");
-				return count;
+				retval = count;
+				goto out;
 			}
 			skb_reserve(skb, hl);
 			if (copy_from_user(skb_put(skb, count), buf, count))
 			{
 				kfree_skb(skb);
-				return -EFAULT;
+				retval = -EFAULT;
+				goto out;
 			}
 			if (is->debug & 0x40) {
 				printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len);
@@ -785,7 +823,11 @@
 			isdn_net_write_super(lp, skb);
 		}
 	}
-	return count;
+	retval = count;
+	
+ out:
+	unlock_kernel();
+	return retval;
 }
 
 /*
diff -u --recursive --new-file v2.5.2/linux/drivers/isdn/isdn_ppp.h linux/drivers/isdn/isdn_ppp.h
--- v2.5.2/linux/drivers/isdn/isdn_ppp.h	Sun Sep 30 12:26:06 2001
+++ linux/drivers/isdn/isdn_ppp.h	Thu Jan 17 14:04:15 2002
@@ -12,9 +12,13 @@
 #include <linux/ppp_defs.h>     /* for PPP_PROTOCOL */
 #include <linux/isdn_ppp.h>	/* for isdn_ppp info */
 
-extern int isdn_ppp_read(int, struct file *, char *, int);
-extern int isdn_ppp_write(int, struct file *, const char *, int);
-extern int isdn_ppp_open(int, struct file *);
+extern int isdn_ppp_open(struct inode *, struct file *);
+extern int isdn_ppp_release(struct inode *, struct file *);
+extern int isdn_ppp_read(struct file *, char *, int, loff_t *off);
+extern int isdn_ppp_write(struct file *, const char *, int, loff_t *off);
+extern int isdn_ppp_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+extern unsigned int isdn_ppp_poll(struct file *, struct poll_table_struct *);
+
 extern int isdn_ppp_init(void);
 extern void isdn_ppp_cleanup(void);
 extern int isdn_ppp_free(isdn_net_local *);
@@ -22,9 +26,6 @@
 extern int isdn_ppp_xmit(struct sk_buff *, struct net_device *);
 extern void isdn_ppp_receive(isdn_net_dev *, isdn_net_local *, struct sk_buff *);
 extern int isdn_ppp_dev_ioctl(struct net_device *, struct ifreq *, int);
-extern unsigned int isdn_ppp_poll(struct file *, struct poll_table_struct *);
-extern int isdn_ppp_ioctl(int, struct file *, unsigned int, unsigned long);
-extern void isdn_ppp_release(int, struct file *);
 extern int isdn_ppp_dial_slave(char *);
 extern void isdn_ppp_wakeup_daemon(isdn_net_local *);
 
diff -u --recursive --new-file v2.5.2/linux/drivers/md/md.c linux/drivers/md/md.c
--- v2.5.2/linux/drivers/md/md.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/md/md.c	Tue Jan 15 13:53:51 2002
@@ -3458,8 +3458,7 @@
 		 * about not overloading the IO subsystem. (things like an
 		 * e2fsck being done on the RAID array should execute fast)
 		 */
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 
 		currspeed = (j-mddev->resync_mark_cnt)/2/((jiffies-mddev->resync_mark)/HZ +1) +1;
 
diff -u --recursive --new-file v2.5.2/linux/drivers/media/radio/radio-sf16fmi.c linux/drivers/media/radio/radio-sf16fmi.c
--- v2.5.2/linux/drivers/media/radio/radio-sf16fmi.c	Sun Sep 30 12:26:06 2001
+++ linux/drivers/media/radio/radio-sf16fmi.c	Tue Jan 15 13:53:51 2002
@@ -94,8 +94,7 @@
 	for(i=0; i< 100; i++)
 	{
 		udelay(1400);
-		if(current->need_resched)
-			schedule();
+		cond_resched();
 	}
 /* If this becomes allowed use it ... 	
 	current->state = TASK_UNINTERRUPTIBLE;
@@ -121,8 +120,7 @@
 	for(i=0; i< 100; i++)
 	{
 		udelay(1400);
-		if(current->need_resched)
-			schedule();
+		cond_resched();
 	}
 /* If this becomes allowed use it ... 	
 	current->state = TASK_UNINTERRUPTIBLE;
diff -u --recursive --new-file v2.5.2/linux/drivers/media/video/bttv-driver.c linux/drivers/media/video/bttv-driver.c
--- v2.5.2/linux/drivers/media/video/bttv-driver.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/media/video/bttv-driver.c	Tue Jan 15 10:56:35 2002
@@ -2037,7 +2037,7 @@
  *    But e.g. pte_alloc() does not work in modules ... :-(
  */
 
-static int do_bttv_mmap(struct bttv *btv, const char *adr, unsigned long size)
+static int do_bttv_mmap(struct vm_area_struct *vma, struct bttv *btv, const char *adr, unsigned long size)
 {
         unsigned long start=(unsigned long) adr;
         unsigned long page,pos;
@@ -2051,7 +2051,7 @@
         pos=(unsigned long) btv->fbuffer;
         while (size > 0) {
                 page = kvirt_to_pa(pos);
-                if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
+                if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
                         return -EAGAIN;
                 start+=PAGE_SIZE;
                 pos+=PAGE_SIZE;
@@ -2060,13 +2060,13 @@
         return 0;
 }
 
-static int bttv_mmap(struct video_device *dev, const char *adr, unsigned long size)
+static int bttv_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr, unsigned long size)
 {
         struct bttv *btv=(struct bttv *)dev;
         int r;
 
         down(&btv->lock);
-        r=do_bttv_mmap(btv, adr, size);
+        r=do_bttv_mmap(vma, btv, adr, size);
         up(&btv->lock);
         return r;
 }
diff -u --recursive --new-file v2.5.2/linux/drivers/media/video/c-qcam.c linux/drivers/media/video/c-qcam.c
--- v2.5.2/linux/drivers/media/video/c-qcam.c	Sun Sep 30 12:26:06 2001
+++ linux/drivers/media/video/c-qcam.c	Tue Jan 15 13:53:51 2002
@@ -425,8 +425,7 @@
 		wantlen -= t;
 		if (t < s)
 			break;
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 	}
 
 	len = outptr;
@@ -445,8 +444,7 @@
 		int l;
 		do {
 			l = qcam_read_bytes(q, tmpbuf, 3);
-			if (current->need_resched)
-				schedule();
+			cond_resched();
 		} while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e));
 		if (force_rgb) {
 			if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
@@ -478,8 +476,7 @@
 		int l;
 		do {
 			l = qcam_read_bytes(q, tmpbuf, 1);
-			if (current->need_resched)
-				schedule();
+			cond_resched();
 		} while (l && tmpbuf[0] == 0x7e);
 		l = qcam_read_bytes(q, tmpbuf+1, 2);
 		if (force_rgb) {
diff -u --recursive --new-file v2.5.2/linux/drivers/media/video/cpia.c linux/drivers/media/video/cpia.c
--- v2.5.2/linux/drivers/media/video/cpia.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/media/video/cpia.c	Tue Jan 15 13:53:51 2002
@@ -2147,8 +2147,7 @@
 			/* loop until image ready */
 			do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
 			while (cam->params.status.streamState != STREAM_READY) {
-				if (current->need_resched)
-					schedule();
+				cond_resched();
 
 				current->state = TASK_INTERRUPTIBLE;
 
@@ -2163,8 +2162,7 @@
 		}
 
 		/* grab image from camera */
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 
 		oldjif = jiffies;
 		image_size = cam->ops->streamRead(cam->lowlevel_data,
@@ -2189,8 +2187,7 @@
 		/* decompress and convert image to by copying it from
 		 * raw_image to decompressed_frame
 		 */
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 
 		cam->image_size = parse_picture(cam, image_size);
 		if (cam->image_size <= 0)
@@ -2972,7 +2969,7 @@
 } 
 
 /* FIXME */
-static int cpia_mmap(struct video_device *dev, const char *adr,
+static int cpia_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr,
                      unsigned long size)
 {
 	unsigned long start = (unsigned long)adr;
@@ -3005,7 +3002,7 @@
 	pos = (unsigned long)(cam->frame_buf);
 	while (size > 0) {
 		page = kvirt_to_pa(pos);
-		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
+		if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
 			up(&cam->busy_lock);
 			return -EAGAIN;
 		}
diff -u --recursive --new-file v2.5.2/linux/drivers/media/video/cpia_pp.c linux/drivers/media/video/cpia_pp.c
--- v2.5.2/linux/drivers/media/video/cpia_pp.c	Thu Oct 25 13:53:47 2001
+++ linux/drivers/media/video/cpia_pp.c	Tue Jan 15 13:53:51 2002
@@ -392,7 +392,7 @@
 	endseen = 0;
 	block_size = PARPORT_CHUNK_SIZE;
 	while( !cam->image_complete ) {
-		if(current->need_resched)  schedule();
+		cond_resched();
 		
 		new_bytes = cpia_pp_read(cam->port, buffer, block_size );
 		if( new_bytes <= 0 ) {
diff -u --recursive --new-file v2.5.2/linux/drivers/media/video/meye.c linux/drivers/media/video/meye.c
--- v2.5.2/linux/drivers/media/video/meye.c	Thu Oct 25 13:53:47 2001
+++ linux/drivers/media/video/meye.c	Tue Jan 15 10:56:35 2002
@@ -1240,7 +1240,7 @@
 	return 0;
 }
 
-static int meye_mmap(struct video_device *dev, const char *adr, 
+static int meye_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr, 
 		     unsigned long size) {
 	unsigned long start=(unsigned long) adr;
 	unsigned long page,pos;
@@ -1263,7 +1263,7 @@
 
 	while (size > 0) {
 		page = kvirt_to_pa(pos);
-		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
+		if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
 			up(&meye.lock);
 			return -EAGAIN;
 		}
diff -u --recursive --new-file v2.5.2/linux/drivers/media/video/planb.c linux/drivers/media/video/planb.c
--- v2.5.2/linux/drivers/media/video/planb.c	Thu Oct 25 13:53:47 2001
+++ linux/drivers/media/video/planb.c	Tue Jan 15 10:56:35 2002
@@ -1994,7 +1994,7 @@
 	return 0;
 }
 
-static int planb_mmap(struct video_device *dev, const char *adr, unsigned long size)
+static int planb_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr, unsigned long size)
 {
 	int i;
 	struct planb *pb = (struct planb *)dev;
@@ -2008,7 +2008,7 @@
 			return err;
 	}
 	for (i = 0; i < pb->rawbuf_size; i++) {
-		if (remap_page_range(start, virt_to_phys((void *)pb->rawbuf[i]),
+		if (remap_page_range(vma, start, virt_to_phys((void *)pb->rawbuf[i]),
 						PAGE_SIZE, PAGE_SHARED))
 			return -EAGAIN;
 		start += PAGE_SIZE;
diff -u --recursive --new-file v2.5.2/linux/drivers/media/video/saa5249.c linux/drivers/media/video/saa5249.c
--- v2.5.2/linux/drivers/media/video/saa5249.c	Sun Sep 30 12:26:06 2001
+++ linux/drivers/media/video/saa5249.c	Tue Jan 15 13:53:51 2002
@@ -127,11 +127,7 @@
 #define MAX(a, b) ((a) > (b) ? (a) : (b))
 #endif
 
-#define RESCHED \
-        do { \
-          if (current->need_resched) \
-            schedule(); \
-        } while (0)
+#define RESCHED do { cond_resched(); } while(0)
 
 static struct video_device saa_template;	/* Declared near bottom */
 
diff -u --recursive --new-file v2.5.2/linux/drivers/media/video/videodev.c linux/drivers/media/video/videodev.c
--- v2.5.2/linux/drivers/media/video/videodev.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/media/video/videodev.c	Tue Jan 15 10:56:35 2002
@@ -206,7 +206,7 @@
 	struct video_device *vfl=video_device[minor(file->f_dentry->d_inode->i_rdev)];
 	if(vfl->mmap) {
 		lock_kernel();
-		ret = vfl->mmap(vfl, (char *)vma->vm_start, 
+		ret = vfl->mmap(vma, vfl, (char *)vma->vm_start, 
 				(unsigned long)(vma->vm_end-vma->vm_start));
 		unlock_kernel();
 	}
diff -u --recursive --new-file v2.5.2/linux/drivers/media/video/zr36067.c linux/drivers/media/video/zr36067.c
--- v2.5.2/linux/drivers/media/video/zr36067.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/media/video/zr36067.c	Tue Jan 15 10:56:35 2002
@@ -4274,7 +4274,7 @@
  *
  */
 
-static int do_zoran_mmap(struct zoran *zr, const char *adr,
+static int do_zoran_mmap(struct vm_area_struct *vma, struct zoran *zr, const char *adr,
 		      unsigned long size)
 {
 	unsigned long start = (unsigned long) adr;
@@ -4321,7 +4321,7 @@
 				    frag_tab[2 * j];
 				page = virt_to_phys(bus_to_virt(pos));	/* should just be pos on i386 */
 				if (remap_page_range
-				    (start, page, todo, PAGE_SHARED)) {
+				    (vma, start, page, todo, PAGE_SHARED)) {
 					printk(KERN_ERR
 					       "%s: zoran_mmap(V4L): remap_page_range failed\n",
 					       zr->name);
@@ -4362,7 +4362,7 @@
 			       ("V4L remap page range %d 0x%lx %ld to 0x%lx\n",
 				i, page, todo, start));
 			if (remap_page_range
-			    (start, page, todo, PAGE_SHARED)) {
+			    (vma, start, page, todo, PAGE_SHARED)) {
 				printk(KERN_ERR
 				       "%s: zoran_mmap(V4L): remap_page_range failed\n",
 				       zr->name);
@@ -4377,14 +4377,14 @@
 	return 0;
 }
 
-static int zoran_mmap(struct video_device *dev, const char *adr,
+static int zoran_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr,
 		      unsigned long size)
 {
 	int err;
 	struct zoran *zr = (struct zoran *) dev;
 	
 	down(&zr->sem);
-	err = do_zoran_mmap(zr, adr, size);
+	err = do_zoran_mmap(vma, zr, adr, size);
 	up(&zr->sem);
 		
 	return err;
diff -u --recursive --new-file v2.5.2/linux/drivers/media/video/zr36120.c linux/drivers/media/video/zr36120.c
--- v2.5.2/linux/drivers/media/video/zr36120.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/media/video/zr36120.c	Tue Jan 15 10:56:35 2002
@@ -1467,7 +1467,7 @@
 }
 
 static
-int zoran_mmap(struct video_device* dev, const char* adr, unsigned long size)
+int zoran_mmap(struct vm_area_struct *vma, struct video_device* dev, const char* adr, unsigned long size)
 {
 	struct zoran* ztv = (struct zoran*)dev;
 	unsigned long start = (unsigned long)adr;
@@ -1483,7 +1483,7 @@
 	pos = (unsigned long)ztv->fbuffer;
 	while (size>0) {
 		unsigned long page = virt_to_phys((void*)pos);
-		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
+		if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
 			return -EAGAIN;
 		start += PAGE_SIZE;
 		pos += PAGE_SIZE;
diff -u --recursive --new-file v2.5.2/linux/drivers/message/fusion/mptscsih.c linux/drivers/message/fusion/mptscsih.c
--- v2.5.2/linux/drivers/message/fusion/mptscsih.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/message/fusion/mptscsih.c	Tue Jan 15 10:52:11 2002
@@ -246,9 +246,9 @@
 		mf_chk = search_taskQ(1,sc,MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK);
 		if (mf_chk != NULL) {
 			sc->result = DID_ABORT << 16;
-			spin_lock_irqsave(&sc->host->host_lock, flags);
+			spin_lock_irqsave(sc->host->host_lock, flags);
 			sc->scsi_done(sc);
-			spin_unlock_irqrestore(&sc->host->host_lock, flags);
+			spin_unlock_irqrestore(sc->host->host_lock, flags);
 			return 1;
 		}
 	}
@@ -426,9 +426,9 @@
 					 scsi_to_pci_dma_dir(sc->sc_data_direction));
 		}
 
-		spin_lock_irqsave(&sc->host->host_lock, flags);
+		spin_lock_irqsave(sc->host->host_lock, flags);
 		sc->scsi_done(sc);
-		spin_unlock_irqrestore(&sc->host->host_lock, flags);
+		spin_unlock_irqrestore(sc->host->host_lock, flags);
 	}
 
 	return 1;
@@ -928,9 +928,9 @@
 			}
 			SCpnt->resid = SCpnt->request_bufflen - mpt_sdev->sense_sz;
 			SCpnt->result = 0;
-/*			spin_lock(&SCpnt->host->host_lock);	*/
+/*			spin_lock(SCpnt->host->host_lock);	*/
 			SCpnt->scsi_done(SCpnt);
-/*			spin_unlock(&SCpnt->host->host_lock);	*/
+/*			spin_unlock(SCpnt->host->host_lock);	*/
 			return 0;
 		}
 	}
@@ -1333,9 +1333,9 @@
 	if (ctx2abort == -1) {
 		printk(KERN_ERR MYNAM ": ERROR - ScsiLookup fail(#2) for SCpnt=%p\n", SCpnt);
 		SCpnt->result = DID_SOFT_ERROR << 16;
-		spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+		spin_lock_irqsave(SCpnt->host->host_lock, flags);
 		SCpnt->scsi_done(SCpnt);
-		spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+		spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
 		mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
 	} else {
 		dprintk((KERN_INFO MYNAM ":DbG: ctx2abort = %08x\n", ctx2abort));
@@ -1352,9 +1352,9 @@
 					": WARNING[2] - IOC error (%d) processing TaskMgmt request (mf=%p:sc=%p)\n",
 					i, mf, SCpnt);
 			SCpnt->result = DID_SOFT_ERROR << 16;
-			spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+			spin_lock_irqsave(SCpnt->host->host_lock, flags);
 			SCpnt->scsi_done(SCpnt);
-			spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+			spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
 			mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
 		}
 	}
@@ -1428,9 +1428,9 @@
 				": WARNING[3] - IOC error (%d) processing TaskMgmt request (mf=%p:sc=%p)\n",
 				i, mf, SCpnt);
 		SCpnt->result = DID_SOFT_ERROR << 16;
-		spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+		spin_lock_irqsave(SCpnt->host->host_lock, flags);
 		SCpnt->scsi_done(SCpnt);
-		spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+		spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
 		mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
 	}
 
@@ -1502,9 +1502,9 @@
 				": WARNING[4] - IOC error (%d) processing TaskMgmt request (mf=%p:sc=%p)\n",
 				i, mf, SCpnt);
 		SCpnt->result = DID_SOFT_ERROR << 16;
-		spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+		spin_lock_irqsave(SCpnt->host->host_lock, flags);
 		SCpnt->scsi_done(SCpnt);
-		spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+		spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
 		mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
 	}
 
@@ -1748,9 +1748,9 @@
 			if (ctx2abort == -1) {
 				printk(KERN_ERR MYNAM ": ERROR - ScsiLookup fail(#1) for SCpnt=%p\n", SCpnt);
 				SCpnt->result = DID_SOFT_ERROR << 16;
-				spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+				spin_lock_irqsave(SCpnt->host->host_lock, flags);
 				SCpnt->scsi_done(SCpnt);
-				spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+				spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
 				mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
 				continue;
 			}
@@ -1797,9 +1797,9 @@
 		    != 0) {
 			printk(KERN_WARNING MYNAM ": WARNING[1] - IOC error (%d) processing TaskMgmt request (mf=%p:sc=%p)\n", i, mf, SCpnt);
 			SCpnt->result = DID_SOFT_ERROR << 16;
-			spin_lock_irqsave(&SCpnt->host->host_lock, flags);
+			spin_lock_irqsave(SCpnt->host->host_lock, flags);
 			SCpnt->scsi_done(SCpnt);
-			spin_unlock_irqrestore(&SCpnt->host->host_lock, flags);
+			spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
 			mpt_free_msg_frame(ScsiTaskCtx, hd->ioc->id, mf);
 		} else {
 			/* Spin-Wait for TaskMgmt complete!!! */
diff -u --recursive --new-file v2.5.2/linux/drivers/mtd/chips/amd_flash.c linux/drivers/mtd/chips/amd_flash.c
--- v2.5.2/linux/drivers/mtd/chips/amd_flash.c	Thu Oct  4 15:14:59 2001
+++ linux/drivers/mtd/chips/amd_flash.c	Tue Jan 15 13:53:51 2002
@@ -889,7 +889,7 @@
 
 	times_left = 500000;
 	while (times_left-- && flash_is_busy(map, adr, private->interleave)) { 
-		if (current->need_resched) {
+		if (need_resched()) {
 			spin_unlock_bh(chip->mutex);
 			schedule();
 			spin_lock_bh(chip->mutex);
@@ -1126,7 +1126,7 @@
 		/* Latency issues. Drop the lock, wait a while and retry */
 		spin_unlock_bh(chip->mutex);
 
-		if (current->need_resched)
+		if (need_resched())
 			schedule();
 		else
 			udelay(1);
diff -u --recursive --new-file v2.5.2/linux/drivers/mtd/devices/blkmtd.c linux/drivers/mtd/devices/blkmtd.c
--- v2.5.2/linux/drivers/mtd/devices/blkmtd.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/mtd/devices/blkmtd.c	Mon Jan 14 21:49:42 2002
@@ -265,7 +265,6 @@
   sigfillset(&tsk->blocked);
   recalc_sigpending(tsk);
   spin_unlock_irq(&tsk->sigmask_lock);
-  exit_sighand(tsk);
 
   if(alloc_kiovec(1, &iobuf))
     return 0;
diff -u --recursive --new-file v2.5.2/linux/drivers/mtd/devices/doc2000.c linux/drivers/mtd/devices/doc2000.c
--- v2.5.2/linux/drivers/mtd/devices/doc2000.c	Thu Oct  4 15:14:59 2001
+++ linux/drivers/mtd/devices/doc2000.c	Tue Jan 15 13:53:51 2002
@@ -97,7 +97,7 @@
 			DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n");
 			return -EIO;
 		}
-		if (current->need_resched) {
+		if (need_resched()) {
 			set_current_state(TASK_UNINTERRUPTIBLE);
 			schedule_timeout(1);
 		}
diff -u --recursive --new-file v2.5.2/linux/drivers/mtd/mtdblock.c linux/drivers/mtd/mtdblock.c
--- v2.5.2/linux/drivers/mtd/mtdblock.c	Tue Dec 18 14:56:36 2001
+++ linux/drivers/mtd/mtdblock.c	Mon Jan 14 21:49:42 2002
@@ -472,20 +472,14 @@
 	struct task_struct *tsk = current;
 	DECLARE_WAITQUEUE(wait, tsk);
 
-	tsk->session = 1;
-	tsk->pgrp = 1;
 	/* we might get involved when memory gets low, so use PF_MEMALLOC */
 	tsk->flags |= PF_MEMALLOC;
 	strcpy(tsk->comm, "mtdblockd");
-	tsk->tty = NULL;
 	spin_lock_irq(&tsk->sigmask_lock);
 	sigfillset(&tsk->blocked);
 	recalc_sigpending(tsk);
 	spin_unlock_irq(&tsk->sigmask_lock);
-	exit_mm(tsk);
-	exit_files(tsk);
-	exit_sighand(tsk);
-	exit_fs(tsk);
+	daemonize();
 
 	while (!leaving) {
 		add_wait_queue(&thr_wq, &wait);
diff -u --recursive --new-file v2.5.2/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.5.2/linux/drivers/net/Config.in	Tue Dec 18 14:56:36 2001
+++ linux/drivers/net/Config.in	Tue Jan 15 10:56:35 2002
@@ -10,9 +10,7 @@
 tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER
 tristate 'Universal TUN/TAP device driver support' CONFIG_TUN
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   if [ "$CONFIG_NETLINK" = "y" ]; then
-      tristate 'Ethertap network tap (OBSOLETE)' CONFIG_ETHERTAP
-   fi
+   tristate 'Ethertap network tap (OBSOLETE)' CONFIG_ETHERTAP
 fi
 
 if [ "$CONFIG_ISAPNP" = "y" -o "$CONFIG_ISAPNP" = "m" ]; then
diff -u --recursive --new-file v2.5.2/linux/drivers/net/acenic.c linux/drivers/net/acenic.c
--- v2.5.2/linux/drivers/net/acenic.c	Mon Nov 19 15:19:42 2001
+++ linux/drivers/net/acenic.c	Tue Jan 15 11:48:13 2002
@@ -208,6 +208,8 @@
 	(((u64)(mask) & 0xffffffff00000000) == 0 ? 0 : -EIO)
 #define pci_dma_supported(dev, mask)		\
 	(((u64)(mask) & 0xffffffff00000000) == 0 ? 1 : 0)
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
 
 #elif (LINUX_VERSION_CODE < 0x02040d)
 
@@ -231,6 +233,8 @@
 }
 #define pci_unmap_page(cookie, dma_addr, size, dir)	\
 	pci_unmap_single(cookie, dma_addr, size, dir)
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
 #endif
 
 
@@ -839,9 +843,11 @@
 			struct sk_buff *skb = ap->skb->rx_std_skbuff[i].skb;
 
 			if (skb) {
+				struct ring_info *ringp;
 				dma_addr_t mapping;
 
-				mapping = ap->skb->rx_std_skbuff[i].mapping;
+				ringp = &ap->skb->rx_std_skbuff[i];
+				mapping = pci_unmap_addr(ringp, mapping);
 				pci_unmap_page(ap->pdev, mapping,
 					       ACE_STD_BUFSIZE - (2 + 16),
 					       PCI_DMA_FROMDEVICE);
@@ -856,9 +862,11 @@
 				struct sk_buff *skb = ap->skb->rx_mini_skbuff[i].skb;
 
 				if (skb) {
+					struct ring_info *ringp;
 					dma_addr_t mapping;
 
-					mapping = ap->skb->rx_mini_skbuff[i].mapping;
+					ringp = &ap->skb->rx_mini_skbuff[i];
+					mapping = pci_unmap_addr(ringp,mapping);
 					pci_unmap_page(ap->pdev, mapping,
 						       ACE_MINI_BUFSIZE - (2 + 16),
 						       PCI_DMA_FROMDEVICE);
@@ -872,9 +880,11 @@
 		for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) {
 			struct sk_buff *skb = ap->skb->rx_jumbo_skbuff[i].skb;
 			if (skb) {
+				struct ring_info *ringp;
 				dma_addr_t mapping;
 
-				mapping = ap->skb->rx_jumbo_skbuff[i].mapping;
+				ringp = &ap->skb->rx_jumbo_skbuff[i];
+				mapping = pci_unmap_addr(ringp, mapping);
 				pci_unmap_page(ap->pdev, mapping,
 					       ACE_JUMBO_BUFSIZE - (2 + 16),
 					       PCI_DMA_FROMDEVICE);
@@ -1832,7 +1842,8 @@
 				       ACE_STD_BUFSIZE - (2 + 16),
 				       PCI_DMA_FROMDEVICE);
 		ap->skb->rx_std_skbuff[idx].skb = skb;
-		ap->skb->rx_std_skbuff[idx].mapping = mapping;
+		pci_unmap_addr_set(&ap->skb->rx_std_skbuff[idx],
+				   mapping, mapping);
 
 		rd = &ap->rx_std_ring[idx];
 		set_aceaddr(&rd->addr, mapping);
@@ -1897,7 +1908,8 @@
 				       ACE_MINI_BUFSIZE - (2 + 16),
 				       PCI_DMA_FROMDEVICE);
 		ap->skb->rx_mini_skbuff[idx].skb = skb;
-		ap->skb->rx_mini_skbuff[idx].mapping = mapping;
+		pci_unmap_addr_set(&ap->skb->rx_mini_skbuff[idx],
+				   mapping, mapping);
 
 		rd = &ap->rx_mini_ring[idx];
 		set_aceaddr(&rd->addr, mapping);
@@ -1957,7 +1969,8 @@
 				       ACE_JUMBO_BUFSIZE - (2 + 16),
 				       PCI_DMA_FROMDEVICE);
 		ap->skb->rx_jumbo_skbuff[idx].skb = skb;
-		ap->skb->rx_jumbo_skbuff[idx].mapping = mapping;
+		pci_unmap_addr_set(&ap->skb->rx_jumbo_skbuff[idx],
+				   mapping, mapping);
 
 		rd = &ap->rx_jumbo_ring[idx];
 		set_aceaddr(&rd->addr, mapping);
@@ -2163,7 +2176,9 @@
 
 		skb = rip->skb;
 		rip->skb = NULL;
-		pci_unmap_page(ap->pdev, rip->mapping, mapsize,
+		pci_unmap_page(ap->pdev,
+			       pci_unmap_addr(rip, mapping),
+			       mapsize,
 			       PCI_DMA_FROMDEVICE);
 		skb_put(skb, retdesc->size);
 
@@ -2229,12 +2244,13 @@
 
 		info = ap->skb->tx_skbuff + idx;
 		skb = info->skb;
-		mapping = info->mapping;
+		mapping = pci_unmap_addr(info, mapping);
 
 		if (mapping) {
-			pci_unmap_page(ap->pdev, mapping, info->maplen,
+			pci_unmap_page(ap->pdev, mapping,
+				       pci_unmap_len(info, maplen),
 				       PCI_DMA_TODEVICE);
-			info->mapping = 0;
+			pci_unmap_addr_set(info, mapping, 0);
 		}
 
 		if (skb) {
@@ -2518,13 +2534,14 @@
 
 		info = ap->skb->tx_skbuff + i;
 		skb = info->skb;
-		mapping = info->mapping;
+		mapping = pci_unmap_addr(info, mapping);
 
 		if (mapping) {
 			memset(ap->tx_ring + i, 0, sizeof(struct tx_desc));
-			pci_unmap_page(ap->pdev, mapping, info->maplen,
+			pci_unmap_page(ap->pdev, mapping,
+				       pci_unmap_len(info, maplen),
 				       PCI_DMA_TODEVICE);
-			info->mapping = 0;
+			pci_unmap_addr_set(info, mapping, 0);
 		}
 		if (skb) {
 			dev_kfree_skb(skb);
@@ -2545,7 +2562,6 @@
 	return 0;
 }
 
-
 static inline dma_addr_t
 ace_map_tx_skb(struct ace_private *ap, struct sk_buff *skb,
 	       struct sk_buff *tail, u32 idx)
@@ -2559,8 +2575,8 @@
 
 	info = ap->skb->tx_skbuff + idx;
 	info->skb = tail;
-	info->mapping = mapping;
-	info->maplen = skb->len;
+	pci_unmap_addr_set(info, mapping, mapping);
+	pci_unmap_len_set(info, maplen, skb->len);
 	return mapping;
 }
 
@@ -2661,8 +2677,8 @@
 			} else {
 				info->skb = NULL;
 			}
-			info->mapping = mapping;
-			info->maplen = frag->size;
+			pci_unmap_addr_set(info, mapping, mapping);
+			pci_unmap_len_set(info, maplen, frag->size);
 			ace_load_tx_bd(desc, mapping, flagsize);
 		}
 	}
diff -u --recursive --new-file v2.5.2/linux/drivers/net/acenic.h linux/drivers/net/acenic.h
--- v2.5.2/linux/drivers/net/acenic.h	Mon Nov 19 15:19:42 2001
+++ linux/drivers/net/acenic.h	Tue Jan 15 14:34:38 2002
@@ -585,7 +585,7 @@
 
 struct ring_info {
 	struct sk_buff		*skb;
-	dma_addr_t		mapping;
+	DECLARE_PCI_UNMAP_ADDR(mapping)
 };
 
 
@@ -596,8 +596,8 @@
  */
 struct tx_ring_info {
 	struct sk_buff		*skb;
-	dma_addr_t		mapping;
-	int			maplen;
+	DECLARE_PCI_UNMAP_ADDR(mapping)
+	DECLARE_PCI_UNMAP_LEN(maplen)
 };
 
 
diff -u --recursive --new-file v2.5.2/linux/drivers/net/de2104x.c linux/drivers/net/de2104x.c
--- v2.5.2/linux/drivers/net/de2104x.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/net/de2104x.c	Tue Jan 15 10:52:11 2002
@@ -45,6 +45,7 @@
 #include <linux/rtnetlink.h>
 #include <linux/crc32.h>
 #include <asm/io.h>
+#include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
 
diff -u --recursive --new-file v2.5.2/linux/drivers/net/pcmcia/wavelan.h linux/drivers/net/pcmcia/wavelan.h
--- v2.5.2/linux/drivers/net/pcmcia/wavelan.h	Fri Mar  2 11:02:15 2001
+++ linux/drivers/net/pcmcia/wavelan.h	Tue Jan 15 18:54:35 2002
@@ -88,6 +88,7 @@
  */
 const int	fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 };
 
+
 /*************************** PC INTERFACE ****************************/
 
 /* WaveLAN host interface definitions */
@@ -316,6 +317,7 @@
 /* Calculate offset of a field in the above structure */
 #define	mmwoff(p,f) 	(unsigned short)((void *)(&((mmw_t *)((void *)0 + (p)))->f) - (void *)0)
 
+
 /*
  * Modem Management Controller (MMC) read structure.
  */
@@ -372,6 +374,7 @@
 
 /* Calculate offset of a field in the above structure */
 #define	mmroff(p,f) 	(unsigned short)((void *)(&((mmr_t *)((void *)0 + (p)))->f) - (void *)0)
+
 
 /* Make the two above structures one */
 typedef union mm_t
diff -u --recursive --new-file v2.5.2/linux/drivers/net/pcmcia/wavelan_cs.c linux/drivers/net/pcmcia/wavelan_cs.c
--- v2.5.2/linux/drivers/net/pcmcia/wavelan_cs.c	Fri Nov  9 15:22:54 2001
+++ linux/drivers/net/pcmcia/wavelan_cs.c	Tue Jan 15 18:54:35 2002
@@ -22,7 +22,7 @@
 #ifdef WAVELAN_ROAMING	
  * Roaming support added 07/22/98 by Justin Seger (jseger@media.mit.edu)
  * based on patch by Joe Finney from Lancaster University.
-#endif :-)
+#endif
  *
  * Lucent (formerly AT&T GIS, formerly NCR) WaveLAN PCMCIA card: An
  * Ethernet-like radio transceiver controlled by an Intel 82593 coprocessor.
@@ -37,12 +37,6 @@
  * Apr 2 '98  made changes to bring the i82593 control/int handling in line
  *             with offical specs...
  *
- * Changes:
- * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/08/2000
- * - reorganize kmallocs in wavelan_attach, checking all for failure
- *   and releasing the previous allocations if one fails
- *
- *
  ****************************************************************************
  *   Copyright 1995
  *   Anthony D. Joseph
@@ -72,6 +66,34 @@
 
 /*------------------------------------------------------------------*/
 /*
+ * Wrapper for disabling interrupts.
+ * (note : inline, so optimised away)
+ */
+static inline void
+wv_splhi(net_local *		lp,
+	 unsigned long *	pflags)
+{
+  spin_lock_irqsave(&lp->spinlock, *pflags);
+  /* Note : above does the cli(); itself */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper for re-enabling interrupts.
+ */
+static inline void
+wv_splx(net_local *		lp,
+	unsigned long *		pflags)
+{
+  spin_unlock_irqrestore(&lp->spinlock, *pflags);
+
+  /* Note : enabling interrupts on the hardware is done in wv_ru_start()
+   * via : outb(OP1_INT_ENABLE, LCCR(base));
+   */
+}
+
+/*------------------------------------------------------------------*/
+/*
  * Wrapper for reporting error to cardservices
  */
 static void cs_error(client_handle_t handle, int func, int ret)
@@ -103,7 +125,7 @@
 
 /******************* MODEM MANAGEMENT SUBROUTINES *******************/
 /*
- * Usefull subroutines to manage the modem of the wavelan
+ * Useful subroutines to manage the modem of the wavelan
  */
 
 /*------------------------------------------------------------------*/
@@ -138,7 +160,7 @@
 {
   hacr_write(base, hacr);
   /* delay might only be needed sometimes */
-  mdelay(1L);
+  mdelay(1);
 } /* hacr_write_slow */
 
 /*------------------------------------------------------------------*/
@@ -529,7 +551,7 @@
   lp->curr_point=NULL;                        /* No default WavePoint */
   lp->cell_search=0;
   
-  lp->cell_timer.data=(int)lp;                /* Start cell expiry timer */
+  lp->cell_timer.data=(long)lp;               /* Start cell expiry timer */
   lp->cell_timer.function=wl_cell_expiry;
   lp->cell_timer.expires=jiffies+CELL_TIMEOUT;
   add_timer(&lp->cell_timer);
@@ -569,18 +591,18 @@
 #endif
   
   /* Disable interrupts & save flags */
-  spin_lock_irqsave (&lp->lock, flags);
+  wv_splhi(lp, &flags);
   
   m.w.mmw_loopt_sel = (mode==NWID_PROMISC) ? MMW_LOOPT_SEL_DIS_NWID : 0x00;
   mmc_write(lp->dev->base_addr, (char *)&m.w.mmw_loopt_sel - (char *)&m, (unsigned char *)&m.w.mmw_loopt_sel, 1);
   
-  /* ReEnable interrupts & restore flags */
-  spin_unlock_irqrestore (&lp->lock, flags);
-  
   if(mode==NWID_PROMISC)
     lp->cell_search=1;
   else
-	lp->cell_search=0;
+    lp->cell_search=0;
+
+  /* ReEnable interrupts & restore flags */
+  wv_splx(lp, &flags);
 }
 
 /* Find a record in the WavePoint table matching a given NWID */
@@ -737,7 +759,7 @@
   ioaddr_t              base = lp->dev->base_addr;  
   mm_t                  m;
   unsigned long         flags;
-  
+
   if(wavepoint==lp->curr_point)          /* Sanity check... */
     {
       wv_nwid_filter(!NWID_PROMISC,lp);
@@ -749,16 +771,16 @@
 #endif
  	
   /* Disable interrupts & save flags */
-  spin_lock_irqsave(&lp->lock, flags);
-  
+  wv_splhi(lp, &flags);
+
   m.w.mmw_netw_id_l = wavepoint->nwid & 0xFF;
   m.w.mmw_netw_id_h = (wavepoint->nwid & 0xFF00) >> 8;
   
   mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, (unsigned char *)&m.w.mmw_netw_id_l, 2);
   
   /* ReEnable interrupts & restore flags */
-  spin_unlock_irqrestore (&lp->lock, flags);
-  
+  wv_splx(lp, &flags);
+
   wv_nwid_filter(!NWID_PROMISC,lp);
   lp->curr_point=wavepoint;
 }
@@ -775,6 +797,11 @@
   wavepoint_history *wavepoint=NULL;                /* WavePoint table entry */
   net_local *lp=(net_local *)dev->priv;              /* Device info */
 
+#if 0
+  /* Some people don't need this, some other may need it */
+  nwid=nwid^ntohs(beacon->domain_id);
+#endif
+
 #if WAVELAN_ROAMING_DEBUG > 1
   printk(KERN_DEBUG "WaveLAN: beacon, dev %s:\n",dev->name);
   printk(KERN_DEBUG "Domain: %.4X NWID: %.4X SigQual=%d\n",ntohs(beacon->domain_id),nwid,sigqual);
@@ -832,7 +859,9 @@
 /*------------------------------------------------------------------*/
 /*
  * Routine to synchronously send a command to the i82593 chip. 
- * Should be called with interrupts enabled.
+ * Should be called with interrupts disabled.
+ * (called by wv_packet_write(), wv_ru_stop(), wv_ru_start(),
+ *  wv_82593_config() & wv_diag())
  */
 static int
 wv_82593_cmd(device *	dev,
@@ -841,74 +870,98 @@
 	     int	result)
 {
   ioaddr_t	base = dev->base_addr;
-  net_local *	lp = (net_local *)dev->priv;
   int		status;
+  int		wait_completed;
   long		spin;
-  u_long	flags;
 
   /* Spin until the chip finishes executing its current command (if any) */
+  spin = 1000;
   do
     {
-      spin_lock_irqsave (&lp->lock, flags);
+      /* Time calibration of the loop */
+      udelay(10);
+
+      /* Read the interrupt register */
       outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
       status = inb(LCSR(base));
-      spin_unlock_irqrestore (&lp->lock, flags);
     }
-  while((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE);
+  while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0));
 
-  /* We are waiting for command completion */
-  wv_wait_completed = TRUE;
+  /* If the interrupt hasn't be posted */
+  if(spin <= 0)
+    {
+#ifdef DEBUG_INTERRUPT_ERROR
+      printk(KERN_INFO "wv_82593_cmd: %s timeout (previous command), status 0x%02x\n",
+	     str, status);
+#endif
+      return(FALSE);
+    }
 
   /* Issue the command to the controller */
   outb(cmd, LCCR(base));
 
-  /* If we don't have to check the result of the command */
+  /* If we don't have to check the result of the command
+   * Note : this mean that the irq handler will deal with that */
   if(result == SR0_NO_RESULT)
-    {
-      wv_wait_completed = FALSE;
-      return(TRUE);
-    }
+    return(TRUE);
 
-  /* Busy wait while the LAN controller executes the command.
-   * Note : wv_wait_completed should be volatile */
-  spin = 0;
-  while(wv_wait_completed && (spin++ < 1000))
-    udelay(10);
+  /* We are waiting for command completion */
+  wait_completed = TRUE;
 
-  /* If the interrupt handler hasn't be called */
-  if(wv_wait_completed)
+  /* Busy wait while the LAN controller executes the command. */
+  spin = 1000;
+  do
     {
-      outb(OP0_NOP, LCCR(base));
+      /* Time calibration of the loop */
+      udelay(10);
+
+      /* Read the interrupt register */
+      outb(CR0_STATUS_0 | OP0_NOP, LCCR(base));
       status = inb(LCSR(base));
-      if(status & SR0_INTERRUPT)
+
+      /* Check if there was an interrupt posted */
+      if((status & SR0_INTERRUPT))
 	{
-	  /* There was an interrupt : call the interrupt handler */
-#ifdef DEBUG_INTERRUPT_ERROR
-	  printk(KERN_WARNING "wv_82593_cmd: interrupt handler not installed or interrupt disabled\n");
-#endif
+	  /* Acknowledge the interrupt */
+	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));
 
-	  wavelan_interrupt(dev->irq, (void *) dev,
-			    (struct pt_regs *) NULL);
+	  /* Check if interrupt is a command completion */
+	  if(((status & SR0_BOTH_RX_TX) != SR0_BOTH_RX_TX) &&
+	     ((status & SR0_BOTH_RX_TX) != 0x0) &&
+	     !(status & SR0_RECEPTION))
+	    {
+	      /* Signal command completion */
+	      wait_completed = FALSE;
+	    }
+	  else
+	    {
+	      /* Note : Rx interrupts will be handled later, because we can
+	       * handle multiple Rx packets at once */
+#ifdef DEBUG_INTERRUPT_INFO
+	      printk(KERN_INFO "wv_82593_cmd: not our interrupt\n");
+#endif
+	    }
 	}
-      else
-	{
-	  wv_wait_completed = 0; /* XXX */
+    }
+  while(wait_completed && (spin-- > 0));
+
+  /* If the interrupt hasn't be posted */
+  if(wait_completed)
+    {
 #ifdef DEBUG_INTERRUPT_ERROR
-	  printk(KERN_INFO "wv_82593_cmd: %s timeout, status0 0x%02x\n",
-		 str, status);
+      printk(KERN_INFO "wv_82593_cmd: %s timeout, status 0x%02x\n",
+	     str, status);
 #endif
-	  /* We probably should reset the controller here */
-	  return(FALSE);
-	}
+      return(FALSE);
     }
 
-  /* Check the return code provided by the interrupt handler against
+  /* Check the return code returned by the card (see above) against
    * the expected return code provided by the caller */
-  if((lp->status & SR0_EVENT_MASK) != result)
+  if((status & SR0_EVENT_MASK) != result)
     {
 #ifdef DEBUG_INTERRUPT_ERROR
-      printk(KERN_INFO "wv_82593_cmd: %s failed, status0 = 0x%x\n",
-	     str, lp->status);
+      printk(KERN_INFO "wv_82593_cmd: %s failed, status = 0x%x\n",
+	     str, status);
 #endif
       return(FALSE);
     }
@@ -924,14 +977,16 @@
 static inline int
 wv_diag(device *	dev)
 {
+  int		ret = FALSE;
+
   if(wv_82593_cmd(dev, "wv_diag(): diagnose",
 		  OP0_DIAGNOSE, SR0_DIAGNOSE_PASSED))
-    return(TRUE);
+    ret = TRUE;
 
 #ifdef DEBUG_CONFIG_ERROR
   printk(KERN_INFO "wavelan_cs: i82593 Self Test failed!\n");
 #endif
-  return(FALSE);
+  return(ret);
 } /* wv_diag */
 
 /*------------------------------------------------------------------*/
@@ -951,15 +1006,6 @@
   int		chunk_len;
   char *	buf_ptr = buf;
 
-#ifdef OLDIES
-  /* After having check skb_put (net/core/skbuff.c) in the kernel, it seem
-   * quite safe to remove this... */
-
-  /* If buf is NULL, just increment the ring buffer pointer */
-  if(buf == NULL)
-    return((ring_ptr - RX_BASE + len) % RX_SIZE + RX_BASE);
-#endif
-
   /* Get all the buffer */
   while(len > 0)
     {
@@ -990,70 +1036,32 @@
  * wavelan_interrupt is not an option...), so you may experience
  * some delay sometime...
  */
-static inline void wv_82593_reconfig (device * dev)
+static inline void
+wv_82593_reconfig(device *	dev)
 {
-	net_local *lp = (net_local *) dev->priv;
-	dev_link_t *link = ((net_local *) dev->priv)->link;
+  net_local *		lp = (net_local *)dev->priv;
+  dev_link_t *		link = ((net_local *) dev->priv)->link;
+  unsigned long		flags;
+
+  /* Arm the flag, will be cleard in wv_82593_config() */
+  lp->reconfig_82593 = TRUE;
 
-	/* Check if we can do it now ! */
-	if (!(link->open)) {
-		lp->reconfig_82593 = TRUE;
+  /* Check if we can do it now ! */
+  if((link->open) && (netif_running(dev)) && !(netif_queue_stopped(dev)))
+    {
+      wv_splhi(lp, &flags);	/* Disable interrupts */
+      wv_82593_config(dev);
+      wv_splx(lp, &flags);	/* Re-enable interrupts */
+    }
+  else
+    {
 #ifdef DEBUG_IOCTL_INFO
-		printk (KERN_DEBUG "%s: wv_82593_reconfig(): delayed (link = %d)\n",
-			dev->name, link->open);
+      printk(KERN_DEBUG
+	     "%s: wv_82593_reconfig(): delayed (state = %lX, link = %d)\n",
+	     dev->name, dev->state, link->open);
 #endif
-	} else {
-		netif_stop_queue (dev);
-
-		lp->reconfig_82593 = FALSE;
-		wv_82593_config (dev);
-		netif_wake_queue (dev);
-	}
-}
-
-#ifdef OLDIES
-/*------------------------------------------------------------------*/
-/*
- * Dumps the current i82593 receive buffer to the console.
- */
-static void wavelan_dump(device *dev)
-{
-  ioaddr_t base = dev->base_addr;
-  int i, c;
-
-  /* disable receiver so we can use channel 1 */
-  outb(OP0_RCV_DISABLE, LCCR(base));
-
-  /* reset receive DMA pointer */
-  hacr_write_slow(base, HACR_PWR_STAT | HACR_RX_DMA_RESET);
-  hacr_write(base, HACR_DEFAULT);
-
-  /* dump into receive buffer */
-  wv_82593_cmd(dev, "wavelan_dump(): dump", CR0_CHNL|OP0_DUMP, SR0_DUMP_DONE);
-
-  /* set read pointer to start of receive buffer */
-  outb(0, PIORL(base));
-  outb(0, PIORH(base));
-
-  printk(KERN_DEBUG "wavelan_cs: dump:\n");
-  printk(KERN_DEBUG "     00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
-  for(i = 0; i < 73; i++){
-    if((i % 16) == 0) {
-      printk("\n0x%02x:", i);
-      if (!i) {
-	printk("   ");
-	continue;
-      }
     }
-    c = inb(PIOP(base));
-    printk("%02x ", c);
-  }
-  printk("\n");
-
-  /* enable the receiver again */
-  wv_ru_start(dev);
 }
-#endif
 
 /********************* DEBUG & INFO SUBROUTINES *********************/
 /*
@@ -1171,6 +1179,8 @@
       return;
     }
 
+  wv_splhi(lp, &flags);
+
   /* Read the mmc */
   mmc_out(base, mmwoff(0, mmw_freeze), 1);
   mmc_read(base, 0, (u_char *)&m, sizeof(m));
@@ -1181,6 +1191,8 @@
   lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
 #endif	/* WIRELESS_EXT */
 
+  wv_splx(lp, &flags);
+
   printk(KERN_DEBUG "##### wavelan modem status registers: #####\n");
 #ifdef DEBUG_SHOW_UNUSED
   printk(KERN_DEBUG "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
@@ -1265,6 +1277,7 @@
 wv_dev_show(device *	dev)
 {
   printk(KERN_DEBUG "dev:");
+  printk(" state=%lX,", dev->state);
   printk(" trans_start=%ld,", dev->trans_start);
   printk(" flags=0x%x,", dev->flags);
   printk("\n");
@@ -1404,7 +1417,7 @@
 	  printk("2430.5");
 	  break;
 	default:
-	  printk("unknown");
+	  printk("???");
 	}
     }
 
@@ -1719,7 +1732,7 @@
 	 memcmp(dac, dac_verify, 2 * 2))
 	{
 #ifdef DEBUG_IOCTL_ERROR
-	  printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (?)\n");
+	  printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (??)\n");
 #endif
 	  return -EOPNOTSUPP;
 	}
@@ -1892,7 +1905,7 @@
 #endif
 
   /* Disable interrupts & save flags */
-  spin_lock_irqsave (&lp->lock, flags);
+  wv_splhi(lp, &flags);
 
   /* Look what is the request */
   switch(cmd)
@@ -1968,7 +1981,7 @@
 
     case SIOCGIWFREQ:
       /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
-       * (does it work for everybody XXX - especially old cards...) */
+       * (does it work for everybody ??? - especially old cards...) */
       if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
 	   (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
 	{
@@ -2239,15 +2252,17 @@
 	{
 	  struct iw_range	range;
 
-	  /* Set the length (very important for backward compatibility) */
-	  wrq->u.data.length = sizeof(struct iw_range);
+	   /* Set the length (very important for backward compatibility) */
+	   wrq->u.data.length = sizeof(struct iw_range);
 
-	  /* Set all the info we don't care or don't know about to zero */
-	  memset(&range, 0, sizeof(range));
+	   /* Set all the info we don't care or don't know about to zero */
+	   memset(&range, 0, sizeof(range));
 
-	  /* Set the Wireless Extension versions */
-	  range.we_version_compiled = WIRELESS_EXT;
-	  range.we_version_source = 9;	/* Nothing for us in v10 and v11 */
+#if WIRELESS_EXT > 10
+	   /* Set the Wireless Extension versions */
+	   range.we_version_compiled = WIRELESS_EXT;
+	   range.we_version_source = 9;	/* Nothing for us in v10 and v11 */
+#endif /* WIRELESS_EXT > 10 */
 
 	  /* Set information in the range struct */
 	  range.throughput = 1.4 * 1000 * 1000;	/* don't argue on this ! */
@@ -2517,7 +2532,7 @@
     }
 
   /* ReEnable interrupts & restore flags */
-  spin_unlock_irqrestore (&lp->lock, flags);
+  wv_splx(lp, &flags);
 
 #ifdef DEBUG_IOCTL_TRACE
   printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);
@@ -2543,11 +2558,8 @@
   printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name);
 #endif
 
-  if (lp == NULL) /* XXX will this ever occur? */
-    return NULL;
-
   /* Disable interrupts & save flags */
-  spin_lock_irqsave (&lp->lock, flags);
+  wv_splhi(lp, &flags);
 
   wstats = &lp->wstats;
 
@@ -2573,7 +2585,7 @@
   wstats->discard.misc = 0L;
 
   /* ReEnable interrupts & restore flags */
-  spin_unlock_irqrestore (&lp->lock, flags);
+  wv_splx(lp, &flags);
 
 #ifdef DEBUG_IOCTL_TRACE
   printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name);
@@ -2692,12 +2704,6 @@
   skb->protocol = eth_type_trans(skb, dev);
 
 #ifdef DEBUG_RX_INFO
-  /* Another glitch : Due to the way the GET_PACKET macro is written,
-   * we are not sure to have the same thing in skb->data. On the other
-   * hand, skb->mac.raw is not defined everywhere...
-   * For versions between 1.2.13 and those where skb->mac.raw appear,
-   * I don't have a clue...
-   */
   wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read");
 #endif	/* DEBUG_RX_INFO */
      
@@ -2731,9 +2737,7 @@
 	  wl_roam_gather(dev, skb->data, stats);
 #endif	/* WAVELAN_ROAMING */
 	  
-      /* Spying stuff */
 #ifdef WIRELESS_SPY
-      /* Same as above */
       wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE, stats);
 #endif	/* WIRELESS_SPY */
 #ifdef HISTOGRAM
@@ -2766,6 +2770,7 @@
  * called to do the actual transfer of the card's data including the
  * ethernet header into a packet consisting of an sk_buff chain.
  * (called by wavelan_interrupt())
+ * Note : the spinlock is already grabbed for us and irq are disabled.
  */
 static inline void
 wv_packet_rcv(device *	dev)
@@ -2916,7 +2921,7 @@
   printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length);
 #endif
 
-  spin_lock_irqsave (&lp->lock, flags);
+  wv_splhi(lp, &flags);
 
   /* Check if we need some padding */
   if(clen < ETH_ZLEN)
@@ -2946,15 +2951,7 @@
   /* Keep stats up to date */
   lp->stats.tx_bytes += length;
 
-  /* If watchdog not already active, activate it... */
-  if (!timer_pending(&lp->watchdog))
-    {
-      /* set timer to expire in WATCHDOG_JIFFIES */
-      lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
-      add_timer(&lp->watchdog);
-    }
-
-  spin_unlock_irqrestore (&lp->lock, flags);
+  wv_splx(lp, &flags);
 
 #ifdef DEBUG_TX_INFO
   wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write");
@@ -2963,56 +2960,57 @@
 #ifdef DEBUG_TX_TRACE
   printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name);
 #endif
-
-  netif_start_queue (dev);
 }
 
 /*------------------------------------------------------------------*/
 /*
  * This routine is called when we want to send a packet (NET3 callback)
- * In this routine, we check if the hardware is ready to accept
+ * In this routine, we check if the harware is ready to accept
  * the packet. We also prevent reentrance. Then, we call the function
  * to send the packet...
  */
-static int wavelan_packet_xmit (struct sk_buff *skb,
-				device * dev)
+static int
+wavelan_packet_xmit(struct sk_buff *	skb,
+		    device *		dev)
 {
-	net_local *lp = (net_local *) dev->priv;
+  net_local *		lp = (net_local *)dev->priv;
+  unsigned long		flags;
 
 #ifdef DEBUG_TX_TRACE
-	printk (KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name,
-		(unsigned) skb);
+  printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name,
+	 (unsigned) skb);
 #endif
 
-	/*
-	 * For ethernet, fill in the header.
-	 */
+  /*
+   * Block a timer-based transmit from overlapping a previous transmit.
+   * In other words, prevent reentering this routine.
+   */
+  netif_stop_queue(dev);
 
-	netif_stop_queue (dev);
+  /* If somebody has asked to reconfigure the controller,
+   * we can do it now */
+  if(lp->reconfig_82593)
+    {
+      wv_splhi(lp, &flags);	/* Disable interrupts */
+      wv_82593_config(dev);
+      wv_splx(lp, &flags);	/* Re-enable interrupts */
+      /* Note : the configure procedure was totally synchronous,
+       * so the Tx buffer is now free */
+    }
 
-	/*
-	 * Block a timer-based transmit from overlapping a previous transmit.
-	 * In other words, prevent reentering this routine.
-	 */
-	if (1) {
-		/* If somebody has asked to reconfigure the controller, we can do it now */
-		if (lp->reconfig_82593) {
-			lp->reconfig_82593 = FALSE;
-			wv_82593_config (dev);
-		}
 #ifdef DEBUG_TX_ERROR
-		if (skb->next)
-			printk (KERN_INFO "skb has next\n");
+	if (skb->next)
+		printk(KERN_INFO "skb has next\n");
 #endif
 
-		wv_packet_write (dev, skb->data, skb->len);
-	}
-	dev_kfree_skb (skb);
+  wv_packet_write(dev, skb->data, skb->len);
+
+  dev_kfree_skb(skb);
 
 #ifdef DEBUG_TX_TRACE
-	printk (KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
+  printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
 #endif
-	return (0);
+  return(0);
 }
 
 /********************** HARDWARE CONFIGURATION **********************/
@@ -3165,7 +3163,7 @@
    */
 
   /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
-   * (does it work for everybody XXX - especially old cards...) */
+   * (does it work for everybody ??? - especially old cards...) */
   /* Note : WFREQSEL verify that it is able to read from EEprom
    * a sensible frequency (address 0x00) + that MMR_FEE_STATUS_ID
    * is 0xA (Xilinx version) or 0xB (Ariadne version).
@@ -3223,7 +3221,7 @@
 wv_ru_stop(device *	dev)
 {
   ioaddr_t	base = dev->base_addr;
-  net_local *lp = (net_local *) dev->priv;
+  net_local *	lp = (net_local *) dev->priv;
   unsigned long	flags;
   int		status;
   int		spin;
@@ -3232,35 +3230,35 @@
   printk(KERN_DEBUG "%s: ->wv_ru_stop()\n", dev->name);
 #endif
 
+  wv_splhi(lp, &flags);
+
   /* First, send the LAN controller a stop receive command */
   wv_82593_cmd(dev, "wv_graceful_shutdown(): stop-rcv",
 	       OP0_STOP_RCV, SR0_NO_RESULT);
 
   /* Then, spin until the receive unit goes idle */
-  spin = 0;
+  spin = 300;
   do
     {
       udelay(10);
-      spin_lock_irqsave (&lp->lock, flags);
       outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
       status = inb(LCSR(base));
-      spin_unlock_irqrestore (&lp->lock, flags);
     }
-  while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin++ < 300));
+  while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin-- > 0));
 
   /* Now, spin until the chip finishes executing its current command */
   do
     {
       udelay(10);
-      spin_lock_irqsave (&lp->lock, flags);
       outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
       status = inb(LCSR(base));
-      spin_unlock_irqrestore (&lp->lock, flags);
     }
-  while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin++ < 300));
+  while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0));
+
+  wv_splx(lp, &flags);
 
   /* If there was a problem */
-  if(spin > 300)
+  if(spin <= 0)
     {
 #ifdef DEBUG_CONFIG_ERROR
       printk(KERN_INFO "%s: wv_ru_stop(): The chip doesn't want to stop...\n",
@@ -3287,6 +3285,7 @@
 {
   ioaddr_t	base = dev->base_addr;
   net_local *	lp = (net_local *) dev->priv;
+  unsigned long	flags;
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name);
@@ -3300,6 +3299,8 @@
   if(!wv_ru_stop(dev))
     return FALSE;
 
+  wv_splhi(lp, &flags);
+
   /* Now we know that no command is being executed. */
 
   /* Set the receive frame pointer and stop pointer */
@@ -3309,8 +3310,17 @@
   /* Reset ring management.  This sets the receive frame pointer to 1 */
   outb(OP1_RESET_RING_MNGMT, LCCR(base));
 
+#if 0
+  /* XXX the i82593 manual page 6-4 seems to indicate that the stop register
+     should be set as below */
+  /* outb(CR1_STOP_REG_UPDATE|((RX_SIZE - 0x40)>> RX_SIZE_SHIFT),LCCR(base));*/
+#elif 0
+  /* but I set it 0 instead */
+  lp->stop = 0;
+#else
   /* but I set it to 3 bytes per packet less than 8K */
   lp->stop = (0 + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE;
+#endif
   outb(CR1_STOP_REG_UPDATE | (lp->stop >> RX_SIZE_SHIFT), LCCR(base));
   outb(OP1_INT_ENABLE, LCCR(base));
   outb(OP1_SWIT_TO_PORT_0, LCCR(base));
@@ -3326,17 +3336,15 @@
 #ifdef DEBUG_I82593_SHOW
   {
     int	status;
-    unsigned long flags;
-    int	i = 0;
+    int	opri;
+    int	spin = 10000;
 
     /* spin until the chip starts receiving */
     do
       {
-	spin_lock_irqsave (&lp->lock, flags);
 	outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
 	status = inb(LCSR(base));
-	spin_unlock_irqrestore (&lp->lock, flags);
-	if(i++ > 10000)
+	if(spin-- <= 0)
 	  break;
       }
     while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_ACTIVE) &&
@@ -3345,6 +3353,9 @@
 	   (status & SR3_RCV_STATE_MASK), i);
   }
 #endif
+
+  wv_splx(lp, &flags);
+
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name);
 #endif
@@ -3363,6 +3374,7 @@
   ioaddr_t			base = dev->base_addr;
   net_local *			lp = (net_local *) dev->priv;
   struct i82593_conf_block	cfblk;
+  int				ret = TRUE;
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: ->wv_82593_config()\n", dev->name);
@@ -3457,7 +3469,7 @@
   hacr_write(base, HACR_DEFAULT);
   if(!wv_82593_cmd(dev, "wv_82593_config(): configure",
 		   OP0_CONFIGURE, SR0_CONFIGURE_DONE))
-    return(FALSE);
+    ret = FALSE;
 
   /* Initialize adapter's ethernet MAC address */
   outb(TX_BASE & 0xff, PIORL(base));
@@ -3471,7 +3483,7 @@
   hacr_write(base, HACR_DEFAULT);
   if(!wv_82593_cmd(dev, "wv_82593_config(): ia-setup",
 		   OP0_IA_SETUP, SR0_IA_SETUP_DONE))
-    return(FALSE);
+    ret = FALSE;
 
 #ifdef WAVELAN_ROAMING
     /* If roaming is enabled, join the "Beacon Request" multicast group... */
@@ -3508,14 +3520,17 @@
       hacr_write(base, HACR_DEFAULT);
       if(!wv_82593_cmd(dev, "wv_82593_config(): mc-setup",
 		       OP0_MC_SETUP, SR0_MC_SETUP_DONE))
-	return(FALSE);
+	ret = FALSE;
       lp->mc_count = dev->mc_count;	/* remember to avoid repeated reset */
     }
 
+  /* Job done, clear the flag */
+  lp->reconfig_82593 = FALSE;
+
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: <-wv_82593_config()\n", dev->name);
 #endif
-  return(TRUE);
+  return(ret);
 }
 
 /*------------------------------------------------------------------*/
@@ -3594,6 +3609,8 @@
 {
   net_local *		lp = (net_local *) dev->priv;
   ioaddr_t		base = dev->base_addr;
+  unsigned long		flags;
+  int			ret = FALSE;
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: ->wv_hw_config()\n", dev->name);
@@ -3612,50 +3629,78 @@
   if(wv_pcmcia_reset(dev) == FALSE)
     return FALSE;
 
-  /* Power UP the module + reset the modem + reset host adapter
-   * (in fact, reset DMA channels) */
-  hacr_write_slow(base, HACR_RESET);
-  hacr_write(base, HACR_DEFAULT);
+  /* Disable interrupts */
+  wv_splhi(lp, &flags);
 
-  /* Check if the module has been powered up... */
-  if(hasr_read(base) & HASR_NO_CLK)
+  /* Disguised goto ;-) */
+  do
     {
+      /* Power UP the module + reset the modem + reset host adapter
+       * (in fact, reset DMA channels) */
+      hacr_write_slow(base, HACR_RESET);
+      hacr_write(base, HACR_DEFAULT);
+
+      /* Check if the module has been powered up... */
+      if(hasr_read(base) & HASR_NO_CLK)
+	{
 #ifdef DEBUG_CONFIG_ERRORS
-      printk(KERN_WARNING "%s: wv_hw_config(): modem not connected or not a wavelan card\n",
-	     dev->name);
+	  printk(KERN_WARNING "%s: wv_hw_config(): modem not connected or not a wavelan card\n",
+		 dev->name);
 #endif
-      return FALSE;
-    }
+	  break;
+	}
 
-  /* initialize the modem */
-  if(wv_mmc_init(dev) == FALSE)
-    return FALSE;
+      /* initialize the modem */
+      if(wv_mmc_init(dev) == FALSE)
+	{
+#ifdef DEBUG_CONFIG_ERRORS
+	  printk(KERN_WARNING "%s: wv_hw_config(): Can't configure the modem\n",
+		 dev->name);
+#endif
+	  break;
+	}
 
-  /* reset the LAN controller (i82593) */
-  outb(OP0_RESET, LCCR(base));
-  mdelay(1);	/* A bit crude ! */
-
-  /* Initialize the LAN controller */
-  if((wv_82593_config(dev) == FALSE) ||
-     (wv_diag(dev) == FALSE))
-    {
+      /* reset the LAN controller (i82593) */
+      outb(OP0_RESET, LCCR(base));
+      mdelay(1);	/* A bit crude ! */
+
+      /* Initialize the LAN controller */
+      if(wv_82593_config(dev) == FALSE)
+	{
 #ifdef DEBUG_CONFIG_ERRORS
-      printk(KERN_INFO "%s: wv_hw_config(): i82593 init failed\n", dev->name);
+	  printk(KERN_INFO "%s: wv_hw_config(): i82593 init failed\n",
+		 dev->name);
 #endif
-      return FALSE;
-    }
+	  break;
+	}
 
-  /* 
-   * insert code for loopback test here
-   */
+      /* Diagnostic */
+      if(wv_diag(dev) == FALSE)
+	{
+#ifdef DEBUG_CONFIG_ERRORS
+	  printk(KERN_INFO "%s: wv_hw_config(): i82593 diagnostic failed\n",
+		 dev->name);
+#endif
+	  break;
+	}
 
-  /* The device is now configured */
-  lp->configured = 1;
+      /* 
+       * insert code for loopback test here
+       */
+
+      /* The device is now configured */
+      lp->configured = 1;
+      ret = TRUE;
+    }
+  while(0);
+
+  /* Re-enable interrupts */
+  wv_splx(lp, &flags);
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: <-wv_hw_config()\n", dev->name);
 #endif
-  return TRUE;
+  return(ret);
 }
 
 /*------------------------------------------------------------------*/
@@ -3675,10 +3720,6 @@
   printk(KERN_DEBUG "%s: ->wv_hw_reset()\n", dev->name);
 #endif
 
-  /* If watchdog was activated, kill it ! */
-  if (timer_pending(&lp->watchdog))
-    del_timer(&lp->watchdog);
-
   lp->nresets++;
   lp->configured = 0;
   
@@ -3786,13 +3827,13 @@
 	}
 
       /*
-       * Allocate a 4K memory window.  Note that the dev_link_t
+       * Allocate a small memory window.  Note that the dev_link_t
        * structure provides space for one window handle -- if your
        * device needs several windows, you'll need to keep track of
        * the handles in your private data structure, link->priv.
        */
       req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
-      req.Base = 0; req.Size = 0x1000;
+      req.Base = req.Size = 0;
       req.AccessSpeed = mem_speed;
       link->win = (window_handle_t)link->handle;
       i = CardServices(RequestWindow, &link->win, &req);
@@ -3803,7 +3844,7 @@
 	}
 
       dev->rmem_start = dev->mem_start =
-	  (u_long)ioremap(req.Base, 0x1000);
+	  (u_long)ioremap(req.Base, req.Size);
       dev->rmem_end = dev->mem_end = dev->mem_start + req.Size;
 
       mem.CardOffset = 0; mem.Page = 0;
@@ -3817,7 +3858,7 @@
       /* Feed device with this info... */
       dev->irq = link->irq.AssignedIRQ;
       dev->base_addr = link->io.BasePort1;
-      netif_start_queue (dev);
+      netif_start_queue(dev);
 
 #ifdef DEBUG_CONFIG_INFO
       printk(KERN_DEBUG "wv_pcmcia_config: MEMSTART 0x%x IRQ %d IOPORT 0x%x\n",
@@ -3843,7 +3884,7 @@
       return FALSE;
     }
 
-  /* XXX Could you explain me this, Dave ? */
+  strcpy(((net_local *) dev->priv)->node.dev_name, dev->name);
   link->dev = &((net_local *) dev->priv)->node;
 
 #ifdef DEBUG_CONFIG_TRACE
@@ -3887,7 +3928,7 @@
   CardServices(ReleaseIO, link->handle, &link->io);
   CardServices(ReleaseIRQ, link->handle, &link->irq);
 
-  link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING | DEV_STALE_CONFIG);
+  link->state &= ~(DEV_CONFIG | DEV_STALE_CONFIG);
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: <- wv_pcmcia_release()\n", dev->name);
@@ -3896,7 +3937,7 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Sometimes, netwave_detach can't be performed following a call from
+ * Sometimes, wavelan_detach can't be performed following a call from
  * cardmgr (device still open, pcmcia_release not done) and the device
  * is put in a STALE_LINK state and remains in memory.
  *
@@ -3970,7 +4011,19 @@
   lp = (net_local *) dev->priv;
   base = dev->base_addr;
 
-  spin_lock (&lp->lock);
+#ifdef DEBUG_INTERRUPT_INFO
+  /* Check state of our spinlock (it should be cleared) */
+  if(spin_is_locked(&lp->spinlock))
+    printk(KERN_DEBUG
+	   "%s: wavelan_interrupt(): spinlock is already locked !!!\n",
+	   dev->name);
+#endif
+
+  /* Prevent reentrancy. We need to do that because we may have
+   * multiple interrupt handler running concurently.
+   * It is safe because wv_splhi() disable interrupts before aquiring
+   * the spinlock. */
+  spin_lock(&lp->spinlock);
 
   /* Treat all pending interrupts */
   while(1)
@@ -4015,8 +4068,6 @@
 	  break;
 	}
 
-      lp->status = status0;	/* Save current status (for commands) */
-
       /* ----------------- RECEIVING PACKET ----------------- */
       /*
        * When the wavelan signal the reception of a new packet,
@@ -4054,22 +4105,6 @@
        * Most likely : transmission done
        */
 
-      /* If we are already waiting elsewhere for the command to complete */
-      if(wv_wait_completed)
-	{
-#ifdef DEBUG_INTERRUPT_INFO
-	  printk(KERN_DEBUG "%s: wv_interrupt(): command completed\n",
-		 dev->name);
-#endif
-
-	  /* Signal command completion */
-	  wv_wait_completed = 0;
-
-	  /* Acknowledge the interrupt */
-	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));
-	  continue;
-    	}
-
       /* If a transmission has been done */
       if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE ||
 	 (status0 & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE ||
@@ -4081,10 +4116,6 @@
 		   dev->name);
 #endif
 
-	  /* If watchdog was activated, kill it ! */
-	  if(timer_pending(&lp->watchdog))
-	    del_timer(&lp->watchdog);
-
 	  /* Get transmission status */
 	  tx_status = inb(LCSR(base));
 	  tx_status |= (inb(LCSR(base)) << 8);
@@ -4174,7 +4205,7 @@
 	  lp->stats.collisions += (tx_status & TX_NCOL_MASK);
 	  lp->stats.tx_packets++;
 
-	  netif_wake_queue (dev);
+	  netif_wake_queue(dev);
 	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));	/* Acknowledge the interrupt */
     	} 
       else	/* if interrupt = transmit done or retransmit done */
@@ -4185,9 +4216,9 @@
 #endif
 	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));	/* Acknowledge the interrupt */
     	}
-    }
+    }	/* while(1) */
 
-  spin_unlock_irq (&lp->lock);
+  spin_unlock(&lp->spinlock);
 
 #ifdef DEBUG_INTERRUPT_TRACE
   printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name);
@@ -4196,30 +4227,23 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Watchdog : when we start a transmission, we set a timer in the
- * kernel.  If the transmission complete, this timer is disabled. If
- * it expire, it try to unlock the hardware.
+ * Watchdog: when we start a transmission, a timer is set for us in the
+ * kernel.  If the transmission completes, this timer is disabled. If
+ * the timer expires, we are called and we try to unlock the hardware.
  *
- * Note : this watchdog doesn't work on the same principle as the
- * watchdog in the ISA driver. I make it this way because the overhead
- * of add_timer() and del_timer() is nothing and that it avoid calling
- * the watchdog, saving some CPU... If you want to apply the same
- * watchdog to the ISA driver, you should be a bit carefull, because
- * of the many transmit buffers...
- * This watchdog is also move clever, it try to abort the current
- * command before reseting everything...
+ * Note : This watchdog is move clever than the one in the ISA driver,
+ * because it try to abort the current command before reseting
+ * everything...
+ * On the other hand, it's a bit simpler, because we don't have to
+ * deal with the multiple Tx buffers...
  */
 static void
-wavelan_watchdog(u_long		a)
+wavelan_watchdog(device *	dev)
 {
-  device *		dev;
-  net_local *		lp;
-  ioaddr_t		base;
-  int			spin;
-
-  dev = (device *) a;
-  base = dev->base_addr;
-  lp = (net_local *) dev->priv;
+  net_local *		lp = (net_local *) dev->priv;
+  ioaddr_t		base = dev->base_addr;
+  unsigned long		flags;
+  int			aborted = FALSE;
 
 #ifdef DEBUG_INTERRUPT_TRACE
   printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name);
@@ -4230,21 +4254,21 @@
 	 dev->name);
 #endif
 
-  /* We are waiting for command completion */
-  wv_wait_completed = TRUE;
+  wv_splhi(lp, &flags);
 
   /* Ask to abort the current command */
   outb(OP0_ABORT, LCCR(base));
 
-  /* Busy wait while the LAN controller executes the command.
-   * Note : wv_wait_completed should be volatile */
-  spin = 0;
-  while(wv_wait_completed && (spin++ < 250))
-    udelay(10);
-
-  /* If the interrupt handler hasn't be called or invalid status */
-  if((wv_wait_completed) ||
-     ((lp->status & SR0_EVENT_MASK) != SR0_EXECUTION_ABORTED))
+  /* Wait for the end of the command (a bit hackish) */
+  if(wv_82593_cmd(dev, "wavelan_watchdog(): abort",
+		  OP0_NOP | CR0_STATUS_3, SR0_EXECUTION_ABORTED))
+    aborted = TRUE;
+
+  /* Release spinlock here so that wv_hw_reset() can grab it */
+  wv_splx(lp, &flags);
+
+  /* Check if we were successful in aborting it */
+  if(!aborted)
     {
       /* It seem that it wasn't enough */
 #ifdef DEBUG_INTERRUPT_ERROR
@@ -4269,7 +4293,7 @@
 #endif
 
   /* We are no more waiting for something... */
-  netif_start_queue (dev);
+  netif_wake_queue(dev);
 
 #ifdef DEBUG_INTERRUPT_TRACE
   printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name);
@@ -4322,7 +4346,7 @@
     return FALSE;
   if(!wv_ru_start(dev))
     wv_hw_reset(dev);		/* If problem : reset */
-  netif_start_queue (dev);
+  netif_start_queue(dev);
 
   /* Mark the device as used */
   link->open++;
@@ -4348,7 +4372,6 @@
 wavelan_close(device *	dev)
 {
   dev_link_t *	link = ((net_local *) dev->priv)->link;
-  net_local *	lp = (net_local *)dev->priv;
   ioaddr_t	base = dev->base_addr;
 
 #ifdef DEBUG_CALLBACK_TRACE
@@ -4356,8 +4379,6 @@
 	 (unsigned int) dev);
 #endif
 
-  netif_stop_queue (dev);
-
   /* If the device isn't open, then nothing to do */
   if(!link->open)
     {
@@ -4373,17 +4394,13 @@
     wv_roam_cleanup(dev);
 #endif	/* WAVELAN_ROAMING */
 
-  /* If watchdog was activated, kill it ! */
-  if(timer_pending(&lp->watchdog))
-    del_timer(&lp->watchdog);
-
   link->open--;
   MOD_DEC_USE_COUNT;
 
   /* If the card is still present */
-  if (netif_device_present(dev))
+  if(netif_running(dev))
     {
-      netif_stop_queue (dev);
+      netif_stop_queue(dev);
 
       /* Stop receiving new messages and wait end of transmission */
       wv_ru_stop(dev);
@@ -4404,21 +4421,6 @@
 
 /*------------------------------------------------------------------*/
 /*
- * We never need to do anything when a wavelan device is "initialized"
- * by the net software, because we only register already-found cards.
- */
-static int
-wavelan_init(device *	dev)
-{
-#ifdef DEBUG_CALLBACK_TRACE
-  printk(KERN_DEBUG "<>wavelan_init()\n");
-#endif
-
-  return(0);
-}
-
-/*------------------------------------------------------------------*/
-/*
  * wavelan_attach() creates an "instance" of the driver, allocating
  * local data structures for one device (one interface).  The device
  * is registered with Card Services.
@@ -4445,24 +4447,8 @@
 
   /* Initialize the dev_link_t structure */
   link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
-  if (!link)
-	  return NULL;
-  
-  /* Allocate the generic data structure */
-  dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
-  if (!dev)
-	  goto fail_alloc_dev;
-  
-  /* Allocate the wavelan-specific data structure. */
-  lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL);
-  if (!lp)
-	  goto fail_alloc_dev_priv;
-  
-  memset(lp, 0, sizeof(net_local));
+  if (!link) return NULL;
   memset(link, 0, sizeof(struct dev_link_t));
-  memset(dev, 0, sizeof(struct net_device));
-
-  dev->priv = lp;
 
   /* Unused for the Wavelan */
   link->release.function = &wv_pcmcia_release;
@@ -4492,18 +4478,35 @@
   link->next = dev_list;
   dev_list = link;
 
+  /* Allocate the generic data structure */
+  dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+  if (!dev) {
+      kfree(link);
+      return NULL;
+  }
+  memset(dev, 0x00, sizeof(struct net_device));
   link->priv = link->irq.Instance = dev;
 
+  /* Allocate the wavelan-specific data structure. */
+  dev->priv = lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL);
+  if (!lp) {
+      kfree(link);
+      kfree(dev);
+      return NULL;
+  }
+  memset(lp, 0x00, sizeof(net_local));
+
   /* Init specific data */
-  wv_wait_completed = 0;
-  lp->status = FALSE;
   lp->configured = 0;
   lp->reconfig_82593 = FALSE;
   lp->nresets = 0;
+  /* Multicast stuff */
+  lp->promiscuous = 0;
+  lp->allmulticast = 0;
+  lp->mc_count = 0;
 
-  /* Set the watchdog timer */
-  lp->watchdog.function = wavelan_watchdog;
-  lp->watchdog.data = (unsigned long) dev;
+  /* Init spinlock */
+  spin_lock_init(&lp->spinlock);
 
   /* back links */
   lp->link = link;
@@ -4513,7 +4516,6 @@
   ether_setup(dev);
 
   /* wavelan NET3 callbacks */
-  dev->init = &wavelan_init;
   dev->open = &wavelan_open;
   dev->stop = &wavelan_close;
   dev->hard_start_xmit = &wavelan_packet_xmit;
@@ -4523,14 +4525,16 @@
   dev->set_mac_address = &wavelan_set_mac_address;
 #endif	/* SET_MAC_ADDRESS */
 
+  /* Set the watchdog timer */
+  dev->tx_timeout	= &wavelan_watchdog;
+  dev->watchdog_timeo	= WATCHDOG_JIFFIES;
+
 #ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
   dev->do_ioctl = wavelan_ioctl;	/* wireless extensions */
   dev->get_wireless_stats = wavelan_get_wireless_stats;
 #endif
 
   /* Other specific data */
-  strcpy(dev->name, ((net_local *)dev->priv)->node.dev_name);
-  netif_start_queue (dev);
   dev->mtu = WAVELAN_MTU;
 
   /* Register with Card Services */
@@ -4562,12 +4566,6 @@
 #endif
 
   return link;
-
-fail_alloc_dev_priv:
-  kfree(dev);
-fail_alloc_dev:
-  kfree(link);
-  return NULL;
 }
 
 /*------------------------------------------------------------------*/
@@ -4698,7 +4696,7 @@
 	if(link->state & DEV_CONFIG)
 	  {
 	    /* Accept no more transmissions */
-      	    netif_device_detach(dev);
+	    netif_device_detach(dev);
 
 	    /* Release the card */
 	    wv_pcmcia_release((u_long) link);
@@ -4720,7 +4718,7 @@
 	 * obliged to close nicely the wavelan here. David, could you
 	 * close the device before suspending them ? And, by the way,
 	 * could you, on resume, add a "route add -net ..." after the
-	 * ifconfig up XXX Thanks... */
+	 * ifconfig up ??? Thanks... */
 
 	/* Stop receiving new messages and wait end of transmission */
 	wv_ru_stop(dev);
@@ -4735,8 +4733,7 @@
     	if(link->state & DEV_CONFIG)
 	  {
       	    if(link->open)
-	      	netif_device_detach(dev);
-
+	      netif_device_detach(dev);
       	    CardServices(ReleaseConfiguration, link->handle);
 	  }
 	break;
@@ -4748,7 +4745,7 @@
 	if(link->state & DEV_CONFIG)
 	  {
       	    CardServices(RequestConfiguration, link->handle, &link->conf);
-      	    if(link->open)	/* If RESET -> True, If RESUME -> False XXX */
+      	    if(link->open)	/* If RESET -> True, If RESUME -> False ??? */
 	      {
 		wv_hw_reset(dev);
 		netif_device_attach(dev);
@@ -4838,4 +4835,3 @@
 
 module_init(init_wavelan_cs);
 module_exit(exit_wavelan_cs);
-MODULE_LICENSE("Dual BSD/GPL");
diff -u --recursive --new-file v2.5.2/linux/drivers/net/pcmcia/wavelan_cs.h linux/drivers/net/pcmcia/wavelan_cs.h
--- v2.5.2/linux/drivers/net/pcmcia/wavelan_cs.h	Fri Oct 12 14:21:18 2001
+++ linux/drivers/net/pcmcia/wavelan_cs.h	Tue Jan 15 18:54:35 2002
@@ -34,6 +34,25 @@
  *	I try to maintain a web page with the Wireless LAN Howto at :
  *	    http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html
  *
+ * SMP
+ * ---
+ *	We now are SMP compliant (I eventually fixed the remaining bugs).
+ *	The driver has been tested on a dual P6-150 and survived my usual
+ *	set of torture tests.
+ *	Anyway, I spent enough time chasing interrupt re-entrancy during
+ *	errors or reconfigure, and I designed the locked/unlocked sections
+ *	of the driver with great care, and with the recent addition of
+ *	the spinlock (thanks to the new API), we should be quite close to
+ *	the truth.
+ *	The SMP/IRQ locking is quite coarse and conservative (i.e. not fast),
+ *	but better safe than sorry (especially at 2 Mb/s ;-).
+ *
+ *	I have also looked into disabling only our interrupt on the card
+ *	(via HACR) instead of all interrupts in the processor (via cli),
+ *	so that other driver are not impacted, and it look like it's
+ *	possible, but it's very tricky to do right (full of races). As
+ *	the gain would be mostly for SMP systems, it can wait...
+ *
  * Debugging and options
  * ---------------------
  *	You will find below a set of '#define" allowing a very fine control
@@ -122,7 +141,7 @@
  * Yunzhou Li <yunzhou@strat.iol.unh.edu> finished is work.
  * Joe Finney <joe@comp.lancs.ac.uk> patched the driver to start
  * correctly 2.00 cards (2.4 GHz with frequency selection).
- * David Hinds <dhinds@pcmcia.sourceforge.org> integrated the whole in his
+ * David Hinds <dahinds@users.sourceforge.net> integrated the whole in his
  * Pcmcia package (+ bug corrections).
  *
  * I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some
@@ -158,8 +177,8 @@
  *
  *    This software was originally developed under Linux 1.2.3
  *	(Slackware 2.0 distribution).
- *    And then under Linux 2.0.x (Debian 1.1 - pcmcia 2.8.18-23) with
- *	HP OmniBook 4000 & 5500.
+ *    And then under Linux 2.0.x (Debian 1.1 -> 2.2 - pcmcia 2.8.18+)
+ *	with an HP OmniBook 4000 and then a 5500.
  *
  *    It is based on other device drivers and information either written
  *    or supplied by:
@@ -174,7 +193,7 @@
  *	Matthew Geier (matthew@cs.su.oz.au),
  *	Remo di Giovanni (remo@cs.su.oz.au),
  *	Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM),
- *	David Hinds <dhinds@pcmcia.sourceforge.org>,
+ *	David Hinds <dahinds@users.sourceforge.net>,
  *	Jan Hoogendoorn (c/o marteijn@lucent.com),
  *      Bruce Janson <bruce@cs.usyd.edu.au>,
  *	Anthony D. Joseph <adj@lcs.mit.edu>,
@@ -349,6 +368,32 @@
  *	- Fix check for root permission (break instead of exit)
  *	- New nwid & encoding setting (Wireless Extension 9)
  *
+ * Changes made for release in 3.1.12 :
+ * ----------------------------------
+ *	- reworked wv_82593_cmd to avoid using the IRQ handler and doing
+ *	  ugly things with interrupts.
+ *	- Add IRQ protection in 82593_config/ru_start/ru_stop/watchdog
+ *	- Update to new network API (softnet - 2.3.43) :
+ *		o replace dev->tbusy (David + me)
+ *		o replace dev->tstart (David + me)
+ *		o remove dev->interrupt (David)
+ *		o add SMP locking via spinlock in splxx (me)
+ *		o add spinlock in interrupt handler (me)
+ *		o use kernel watchdog instead of ours (me)
+ *		o verify that all the changes make sense and work (me)
+ *	- Re-sync kernel/pcmcia versions (not much actually)
+ *	- A few other cleanups (David & me)...
+ *
+ * Changes made for release in 3.1.22 :
+ * ----------------------------------
+ *	- Check that SMP works, remove annoying log message
+ *
+ * Changes made for release in 3.1.24 :
+ * ----------------------------------
+ *	- Fix unfrequent card lockup when watchdog was reseting the hardware :
+ *		o control first busy loop in wv_82593_cmd()
+ *		o Extend spinlock protection in wv_hw_config()
+ *
  * Wishes & dreams:
  * ----------------
  *	- Cleanup and integrate the roaming code
@@ -368,6 +413,7 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/interrupt.h>
+#include <linux/spinlock.h>
 #include <linux/in.h>
 #include <linux/delay.h>
 #include <asm/uaccess.h>
@@ -384,7 +430,7 @@
 
 #ifdef CONFIG_NET_PCMCIA_RADIO
 #include <linux/wireless.h>		/* Wireless extensions */
-#endif	/* CONFIG_NET_PCMCIA_RADIO */
+#endif
 
 /* Pcmcia headers that we need */
 #include <pcmcia/cs_types.h>
@@ -437,7 +483,7 @@
 #undef DEBUG_RX_INFO		/* Header of the transmitted packet */
 #undef DEBUG_RX_FAIL		/* Normal failure conditions */
 #define DEBUG_RX_ERROR		/* Unexpected conditions */
-#undef DEBUG_PACKET_DUMP	/* Dump packet on the screen */
+#undef DEBUG_PACKET_DUMP	32	/* Dump packet on the screen */
 #undef DEBUG_IOCTL_TRACE	/* Misc call by Linux */
 #undef DEBUG_IOCTL_INFO		/* Various debug info */
 #define DEBUG_IOCTL_ERROR	/* What's going wrong */
@@ -452,7 +498,7 @@
 /************************ CONSTANTS & MACROS ************************/
 
 #ifdef DEBUG_VERSION_SHOW
-static const char *version = "wavelan_cs.c : v21 (wireless extensions) 18/10/99\n";
+static const char *version = "wavelan_cs.c : v23 (SMP + wireless extensions) 20/12/00\n";
 #endif
 
 /* Watchdog temporisation */
@@ -557,9 +603,9 @@
  */
 struct net_local
 {
-  spinlock_t	lock;
   dev_node_t 	node;		/* ???? What is this stuff ???? */
   device *	dev;		/* Reverse link... */
+  spinlock_t	spinlock;	/* Serialize access to the hardware (SMP) */
   dev_link_t *	link;		/* pcmcia structure */
   en_stats	stats;		/* Ethernet interface statistics */
   int		nresets;	/* Number of hw resets */
@@ -568,9 +614,7 @@
   u_char	promiscuous;	/* Promiscuous mode */
   u_char	allmulticast;	/* All Multicast mode */
   int		mc_count;	/* Number of multicast addresses */
-  timer_list	watchdog;	/* To avoid blocking state */
 
-  u_char        status;		/* Current i82593 status */
   int   	stop;		/* Current i82593 Stop Hit Register */
   int   	rfp;		/* Last DMA machine receive pointer */
   int		overrunning;	/* Receiver overrun flag */
@@ -617,8 +661,14 @@
 #endif	/* WAVELAN_ROAMING */
 
 /* ----------------------- MISC SUBROUTINES ------------------------ */
+static inline void
+	wv_splhi(net_local *,		/* Disable interrupts */
+		 unsigned long *);	/* flags */
+static inline void
+	wv_splx(net_local *,		/* ReEnable interrupts */
+		unsigned long *);	/* flags */
 static void
-	cs_error(client_handle_t, /* Report error to cardmgr */
+	cs_error(client_handle_t,	/* Report error to cardmgr */
 		 int,
 		 int);
 /* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */
@@ -722,16 +772,15 @@
 	wv_flush_stale_links(void);	/* "detach" all possible devices */
 /* ---------------------- INTERRUPT HANDLING ---------------------- */
 static void
-wavelan_interrupt(int,	/* Interrupt handler */
-		  void *,
-		  struct pt_regs *);
+	wavelan_interrupt(int,	/* Interrupt handler */
+			  void *,
+			  struct pt_regs *);
 static void
-	wavelan_watchdog(u_long);	/* Transmission watchdog */
+	wavelan_watchdog(device *);	/* Transmission watchdog */
 /* ------------------- CONFIGURATION CALLBACKS ------------------- */
 static int
 	wavelan_open(device *),		/* Open the device */
-	wavelan_close(device *),	/* Close the device */
-	wavelan_init(device *);		/* Do nothing */
+	wavelan_close(device *);	/* Close the device */
 static dev_link_t *
 	wavelan_attach(void);		/* Create a new device */
 static void
@@ -744,11 +793,7 @@
 /**************************** VARIABLES ****************************/
 
 static dev_info_t dev_info = "wavelan_cs";
-static dev_link_t *dev_list;		/* Linked list of devices */
-
-/* WARNING : the following variable MUST be volatile
- * It is used by wv_82593_cmd to syncronise with wavelan_interrupt */ 
-static volatile int	wv_wait_completed;
+static dev_link_t *dev_list = NULL;	/* Linked list of devices */
 
 /*
  * Parameters that can be set with 'insmod'
@@ -761,7 +806,7 @@
 static int 	irq_list[4] = { -1 };
 
 /* Shared memory speed, in ns */
-static int	mem_speed;
+static int	mem_speed = 0;
 
 /* New module interface */
 MODULE_PARM(irq_mask, "i");
@@ -770,9 +815,11 @@
 
 #ifdef WAVELAN_ROAMING		/* Conditional compile, see above in options */
 /* Enable roaming mode ? No ! Please keep this to 0 */
-static int	do_roaming;
+static int	do_roaming = 0;
 MODULE_PARM(do_roaming, "i");
 #endif	/* WAVELAN_ROAMING */
+
+MODULE_LICENSE("GPL");
 
 #endif	/* WAVELAN_CS_H */
 
diff -u --recursive --new-file v2.5.2/linux/drivers/net/sunbmac.c linux/drivers/net/sunbmac.c
--- v2.5.2/linux/drivers/net/sunbmac.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/net/sunbmac.c	Tue Jan 15 10:52:11 2002
@@ -1,4 +1,4 @@
-/* $Id: sunbmac.c,v 1.28 2001/10/21 06:35:29 davem Exp $
+/* $Id: sunbmac.c,v 1.30 2002/01/15 06:48:55 davem Exp $
  * sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
@@ -986,7 +986,7 @@
 	unsigned long bregs = bp->bregs;
 	struct dev_mc_list *dmi = dev->mc_list;
 	char *addrs;
-	int i, j, bit, byte;
+	int i;
 	u32 tmp, crc;
 
 	/* Disable the receiver.  The bit self-clears when
diff -u --recursive --new-file v2.5.2/linux/drivers/net/sungem.c linux/drivers/net/sungem.c
--- v2.5.2/linux/drivers/net/sungem.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/net/sungem.c	Tue Jan 15 10:52:11 2002
@@ -1,4 +1,4 @@
-/* $Id: sungem.c,v 1.44 2001/12/08 04:06:27 davem Exp $
+/* $Id: sungem.c,v 1.48 2002/01/15 06:26:37 davem Exp $
  * sungem.c: Sun GEM ethernet driver.
  *
  * Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com)
@@ -58,6 +58,10 @@
 
 #include "sungem.h"
 
+#define DEFAULT_MSG	(NETIF_MSG_DRV		| \
+			 NETIF_MSG_PROBE	| \
+			 NETIF_MSG_LINK)
+
 #define DRV_NAME	"sungem"
 #define DRV_VERSION	"0.96"
 #define DRV_RELDATE	"11/17/01"
@@ -71,9 +75,11 @@
 MODULE_LICENSE("GPL");
 
 MODULE_PARM(gem_debug, "i");
-MODULE_PARM_DESC(gem_debug, "(ignored)");
+MODULE_PARM_DESC(gem_debug, "bitmapped message enable number");
 MODULE_PARM(link_mode, "i");
+MODULE_PARM_DESC(link_mode, "default link mode");
 
+int gem_debug = -1;
 static int link_mode;
 
 static u16 link_modes[] __devinitdata = {
@@ -89,10 +95,9 @@
 #define GEM_MODULE_NAME	"gem"
 #define PFX GEM_MODULE_NAME ": "
 
-#ifdef GEM_DEBUG
-int gem_debug = GEM_DEBUG;
-#else
-int gem_debug = 1;
+/* Until this gets merged from 2.4.x... */
+#ifndef PCI_DEVICE_ID_APPLE_UNI_N_GMACP
+#define PCI_DEVICE_ID_APPLE_UNI_N_GMACP 0x0024
 #endif
 
 static struct pci_device_id gem_pci_tbl[] __devinitdata = {
@@ -110,6 +115,8 @@
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_GMAC,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_GMACP,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{0, }
 };
 
@@ -175,6 +182,8 @@
 
 static void gem_handle_mif_event(struct gem *gp, u32 reg_val, u32 changed_bits)
 {
+	if (netif_msg_intr(gp))
+		printk(KERN_DEBUG "%s: mif interrupt\n", gp->dev->name);
 }
 
 static int gem_pcs_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status)
@@ -182,6 +191,10 @@
 	u32 pcs_istat = readl(gp->regs + PCS_ISTAT);
 	u32 pcs_miistat;
 
+	if (netif_msg_intr(gp))
+		printk(KERN_DEBUG "%s: pcs interrupt, pcs_istat: 0x%x\n",
+			gp->dev->name, pcs_istat);
+
 	if (!(pcs_istat & PCS_ISTAT_LSC)) {
 		printk(KERN_ERR "%s: PCS irq but no link status change???\n",
 		       dev->name);
@@ -231,6 +244,10 @@
 {
 	u32 txmac_stat = readl(gp->regs + MAC_TXSTAT);
 
+	if (netif_msg_intr(gp))
+		printk(KERN_DEBUG "%s: txmac interrupt, txmac_stat: 0x%x\n",
+			gp->dev->name, txmac_stat);
+
 	/* Defer timer expiration is quite normal,
 	 * don't even log the event.
 	 */
@@ -276,6 +293,10 @@
 {
 	u32 rxmac_stat = readl(gp->regs + MAC_RXSTAT);
 
+	if (netif_msg_intr(gp))
+		printk(KERN_DEBUG "%s: rxmac interrupt, rxmac_stat: 0x%x\n",
+			gp->dev->name, rxmac_stat);
+
 	if (rxmac_stat & MAC_RXSTAT_OFLW) {
 		printk(KERN_ERR "%s: RX MAC fifo overflow.\n",
 		       dev->name);
@@ -302,6 +323,10 @@
 {
 	u32 mac_cstat = readl(gp->regs + MAC_CSTAT);
 
+	if (netif_msg_intr(gp))
+		printk(KERN_DEBUG "%s: mac interrupt, mac_cstat: 0x%x\n",
+			gp->dev->name, mac_cstat);
+
 	/* This interrupt is just for pause frame and pause
 	 * tracking.  It is useful for diagnostics and debug
 	 * but probably by default we will mask these events.
@@ -402,11 +427,17 @@
 {
 	if (gem_status & GREG_STAT_RXNOBUF) {
 		/* Frame arrived, no free RX buffers available. */
+		if (netif_msg_rx_err(gp))
+			printk(KERN_DEBUG "%s: no buffer for rx frame\n",
+				gp->dev->name);
 		gp->net_stats.rx_dropped++;
 	}
 
 	if (gem_status & GREG_STAT_RXTAGERR) {
 		/* corrupt RX tag framing */
+		if (netif_msg_rx_err(gp))
+			printk(KERN_DEBUG "%s: corrupt rx tag framing\n",
+				gp->dev->name);
 		gp->net_stats.rx_errors++;
 
 		goto do_reset;
@@ -455,6 +486,10 @@
 {
 	int entry, limit;
 
+	if (netif_msg_intr(gp))
+		printk(KERN_DEBUG "%s: tx interrupt, gem_status: 0x%x\n",
+			gp->dev->name, gem_status);
+
 	entry = gp->tx_old;
 	limit = ((gem_status & GREG_STAT_TXNR) >> GREG_STAT_TXNR_SHIFT);
 	while (entry != limit) {
@@ -464,6 +499,9 @@
 		u32 dma_len;
 		int frag;
 
+		if (netif_msg_tx_done(gp))
+			printk(KERN_DEBUG "%s: tx done, slot %d\n",
+				gp->dev->name, entry);
 		skb = gp->tx_skbs[entry];
 		if (skb_shinfo(skb)->nr_frags) {
 			int last = entry + skb_shinfo(skb)->nr_frags;
@@ -535,6 +573,10 @@
 {
 	int entry, drops;
 
+	if (netif_msg_intr(gp))
+		printk(KERN_DEBUG "%s: rx interrupt, done: %d, rx_new: %d\n",
+			gp->dev->name, readl(gp->regs + RXDMA_DONE), gp->rx_new);
+
 	entry = gp->rx_new;
 	drops = 0;
 	for (;;) {
@@ -786,6 +828,9 @@
 	if (TX_BUFFS_AVAIL(gp) <= 0)
 		netif_stop_queue(dev);
 
+	if (netif_msg_tx_queued(gp))
+		printk(KERN_DEBUG "%s: tx queued, slot %d, skblen %d\n",
+		       dev->name, entry, skb->len);
 	writel(gp->tx_new, gp->regs + TXDMA_KICK);
 	spin_unlock_irq(&gp->lock);
 
@@ -993,8 +1038,9 @@
 		speed = 1000;
 	}
 
-	printk(KERN_INFO "%s: Link is up at %d Mbps, %s-duplex.\n",
-	       gp->dev->name, speed, (full_duplex ? "full" : "half"));
+	if (netif_msg_link(gp))
+		printk(KERN_INFO "%s: Link is up at %d Mbps, %s-duplex.\n",
+			gp->dev->name, speed, (full_duplex ? "full" : "half"));
 
 	val = (MAC_TXCFG_EIPG0 | MAC_TXCFG_NGU);
 	if (full_duplex) {
@@ -1059,15 +1105,21 @@
 
 static int gem_mdio_link_not_up(struct gem *gp)
 {
+	u16 val;
+	
 	if (gp->lstate == link_force_ret) {
-		printk(KERN_INFO "%s: Autoneg failed again, keeping"
-			" forced mode\n", gp->dev->name);
+		if (netif_msg_link(gp))
+			printk(KERN_INFO "%s: Autoneg failed again, keeping"
+				" forced mode\n", gp->dev->name);
 		phy_write(gp, MII_BMCR, gp->link_fcntl);
 		gp->timer_ticks = 5;
 		gp->lstate = link_force_ok;
 	} else if (gp->lstate == link_aneg) {
-		u16 val = phy_read(gp, MII_BMCR);
+		val = phy_read(gp, MII_BMCR);
 
+		if (netif_msg_link(gp))
+			printk(KERN_INFO "%s: switching to forced 100bt\n",
+				gp->dev->name);
 		/* Try forced modes. */
 		val &= ~(BMCR_ANRESTART | BMCR_ANENABLE);
 		val &= ~(BMCR_FULLDPLX);
@@ -1080,14 +1132,16 @@
 		 * If already at 10Mbps, warn user about the
 		 * situation every 10 ticks.
 		 */
-		u16 val = phy_read(gp, MII_BMCR);
+		val = phy_read(gp, MII_BMCR);
 		if (val & BMCR_SPEED100) {
 			val &= ~BMCR_SPEED100;
 			phy_write(gp, MII_BMCR, val);
 			gp->timer_ticks = 5;
-		} else {
+			if (netif_msg_link(gp))
+				printk(KERN_INFO "%s: switching to forced 10bt\n",
+					gp->dev->name);
+		} else
 			return 1;
-		}
 	}
 	return 0;
 }
@@ -1140,22 +1194,16 @@
 	if (gp->phy_type == phy_mii_mdio0 ||
 	    gp->phy_type == phy_mii_mdio1) {
 		u16 val = phy_read(gp, MII_BMSR);
+		u16 cntl = phy_read(gp, MII_BMCR);
 		int up;
 
 		/* When using autoneg, we really wait for ANEGCOMPLETE or we may
 		 * get a "transcient" incorrect link state
 		 */
-#if 0
-		{
-			u16 cntl = phy_read(gp, MII_BMCR);
-			if (cntl & BMCR_ANENABLE)
-				up = (val & (BMSR_ANEGCOMPLETE | BMSR_LSTATUS)) == (BMSR_ANEGCOMPLETE | BMSR_LSTATUS);
-			else
-				up = (val & BMSR_LSTATUS) != 0;
-		}
-#else
-		up = (val & BMSR_LSTATUS) != 0;
-#endif
+		if (cntl & BMCR_ANENABLE)
+			up = (val & (BMSR_ANEGCOMPLETE | BMSR_LSTATUS)) == (BMSR_ANEGCOMPLETE | BMSR_LSTATUS);
+		else
+			up = (val & BMSR_LSTATUS) != 0;
 		if (up) {
 			/* Ok, here we got a link. If we had it due to a forced
 			 * fallback, and we were configured for autoneg, we do
@@ -1166,8 +1214,9 @@
 				gp->lstate = link_force_ret;
 				gp->link_fcntl = phy_read(gp, MII_BMCR);
 				gp->timer_ticks = 5;
-				printk(KERN_INFO "%s: Got link after fallback, retrying autoneg"
-				       " once...\n", gp->dev->name);
+				if (netif_msg_link(gp))
+					printk(KERN_INFO "%s: Got link after fallback, retrying"
+						" autoneg once...\n", gp->dev->name);
 				phy_write(gp, MII_BMCR,
 					  gp->link_fcntl | BMCR_ANENABLE | BMCR_ANRESTART);
 			} else if (gp->lstate != link_up) {
@@ -1183,7 +1232,9 @@
 			 */
 			if (gp->lstate == link_up) {
 				gp->lstate = link_down;
-				printk(KERN_INFO "%s: Link down\n", gp->dev->name);
+				if (netif_msg_link(gp))
+					printk(KERN_INFO "%s: Link down\n",
+						gp->dev->name);
 				gp->reset_task_pending = 1;
 				schedule_task(&gp->reset_task);
 				restart = 1;
@@ -1650,6 +1701,48 @@
 		       gp->regs + RXDMA_BLANK);
 }
 
+static u32
+gem_setup_multicast(struct gem *gp)
+{
+	u32 rxcfg = 0;
+	int i;
+	
+	if ((gp->dev->flags & IFF_ALLMULTI) ||
+	    (gp->dev->mc_count > 256)) {
+	    	for (i=0; i<16; i++)
+			writel(0xffff, gp->regs + MAC_HASH0 + (i << 2));
+		rxcfg |= MAC_RXCFG_HFE;
+	} else if (gp->dev->flags & IFF_PROMISC) {
+		rxcfg |= MAC_RXCFG_PROM;
+	} else {
+		u16 hash_table[16];
+		u32 crc;
+		struct dev_mc_list *dmi = gp->dev->mc_list;
+		int i;
+
+		for (i = 0; i < 16; i++)
+			hash_table[i] = 0;
+
+		for (i = 0; i < gp->dev->mc_count; i++) {
+			char *addrs = dmi->dmi_addr;
+
+			dmi = dmi->next;
+
+			if (!(*addrs & 1))
+				continue;
+
+ 			crc = ether_crc_le(6, addrs);
+			crc >>= 24;
+			hash_table[crc >> 4] |= 1 << (15 - (crc & 0xf));
+		}
+	    	for (i=0; i<16; i++)
+			writel(hash_table[i], gp->regs + MAC_HASH0 + (i << 2));
+		rxcfg |= MAC_RXCFG_HFE;
+	}
+
+	return rxcfg;
+}
+
 static void gem_init_mac(struct gem *gp)
 {
 	unsigned char *e = &gp->dev->dev_addr[0];
@@ -1690,65 +1783,7 @@
 	writel(0, gp->regs + MAC_AF21MSK);
 	writel(0, gp->regs + MAC_AF0MSK);
 
-	rxcfg = 0;
-	if ((gp->dev->flags & IFF_ALLMULTI) ||
-	    (gp->dev->mc_count > 256)) {
-		writel(0xffff, gp->regs + MAC_HASH0);
-		writel(0xffff, gp->regs + MAC_HASH1);
-		writel(0xffff, gp->regs + MAC_HASH2);
-		writel(0xffff, gp->regs + MAC_HASH3);
-		writel(0xffff, gp->regs + MAC_HASH4);
-		writel(0xffff, gp->regs + MAC_HASH5);
-		writel(0xffff, gp->regs + MAC_HASH6);
-		writel(0xffff, gp->regs + MAC_HASH7);
-		writel(0xffff, gp->regs + MAC_HASH8);
-		writel(0xffff, gp->regs + MAC_HASH9);
-		writel(0xffff, gp->regs + MAC_HASH10);
-		writel(0xffff, gp->regs + MAC_HASH11);
-		writel(0xffff, gp->regs + MAC_HASH12);
-		writel(0xffff, gp->regs + MAC_HASH13);
-		writel(0xffff, gp->regs + MAC_HASH14);
-		writel(0xffff, gp->regs + MAC_HASH15);
-	} else if (gp->dev->flags & IFF_PROMISC) {
-		rxcfg |= MAC_RXCFG_PROM;
-	} else {
-		u16 hash_table[16];
-		u32 crc;
-		struct dev_mc_list *dmi = gp->dev->mc_list;
-		int i;
-
-		for (i = 0; i < 16; i++)
-			hash_table[i] = 0;
-
-		for (i = 0; i < gp->dev->mc_count; i++) {
-			char *addrs = dmi->dmi_addr;
-
-			dmi = dmi->next;
-
-			if (!(*addrs & 1))
-				continue;
-
- 			crc = ether_crc_le(6, addrs);
-			crc >>= 24;
-			hash_table[crc >> 4] |= 1 << (crc & 0xf);
-		}
-		writel(hash_table[0], gp->regs + MAC_HASH0);
-		writel(hash_table[1], gp->regs + MAC_HASH1);
-		writel(hash_table[2], gp->regs + MAC_HASH2);
-		writel(hash_table[3], gp->regs + MAC_HASH3);
-		writel(hash_table[4], gp->regs + MAC_HASH4);
-		writel(hash_table[5], gp->regs + MAC_HASH5);
-		writel(hash_table[6], gp->regs + MAC_HASH6);
-		writel(hash_table[7], gp->regs + MAC_HASH7);
-		writel(hash_table[8], gp->regs + MAC_HASH8);
-		writel(hash_table[9], gp->regs + MAC_HASH9);
-		writel(hash_table[10], gp->regs + MAC_HASH10);
-		writel(hash_table[11], gp->regs + MAC_HASH11);
-		writel(hash_table[12], gp->regs + MAC_HASH12);
-		writel(hash_table[13], gp->regs + MAC_HASH13);
-		writel(hash_table[14], gp->regs + MAC_HASH14);
-		writel(hash_table[15], gp->regs + MAC_HASH15);
-	}
+	rxcfg = gem_setup_multicast(gp);
 
 	writel(0, gp->regs + MAC_NCOLL);
 	writel(0, gp->regs + MAC_FASUCC);
@@ -2041,16 +2076,14 @@
 		schedule();
 	
 	/* Actually stop the chip */
-	if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
+	if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) {
 		gem_stop_phy(gp);
-	else
-		gem_stop(gp);
-
 #ifdef CONFIG_ALL_PPC
-	/* Power down the chip */
-	if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
+		/* Power down the chip */
 		gem_apple_powerdown(gp);
 #endif /* CONFIG_ALL_PPC */
+	} else
+		gem_stop(gp);
 }
 
 static void gem_pm_task(void *data)
@@ -2112,6 +2145,7 @@
 	 */
 	if (request_irq(gp->pdev->irq, gem_interrupt,
 			SA_SHIRQ, dev->name, (void *)dev)) {
+		printk(KERN_ERR "%s: failed to request irq !\n", gp->dev->name);
 #ifdef CONFIG_ALL_PPC
 		if (!hw_was_up && gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
 			gem_apple_powerdown(gp);
@@ -2274,81 +2308,28 @@
 static void gem_set_multicast(struct net_device *dev)
 {
 	struct gem *gp = dev->priv;
-
+	u32 rxcfg, rxcfg_new;
+	int limit = 10000;
+	
 	if (!gp->hw_running)
 		return;
 		
 	netif_stop_queue(dev);
 
-	if ((gp->dev->flags & IFF_ALLMULTI) ||
-	    (gp->dev->mc_count > 256)) {
-		writel(0xffff, gp->regs + MAC_HASH0);
-		writel(0xffff, gp->regs + MAC_HASH1);
-		writel(0xffff, gp->regs + MAC_HASH2);
-		writel(0xffff, gp->regs + MAC_HASH3);
-		writel(0xffff, gp->regs + MAC_HASH4);
-		writel(0xffff, gp->regs + MAC_HASH5);
-		writel(0xffff, gp->regs + MAC_HASH6);
-		writel(0xffff, gp->regs + MAC_HASH7);
-		writel(0xffff, gp->regs + MAC_HASH8);
-		writel(0xffff, gp->regs + MAC_HASH9);
-		writel(0xffff, gp->regs + MAC_HASH10);
-		writel(0xffff, gp->regs + MAC_HASH11);
-		writel(0xffff, gp->regs + MAC_HASH12);
-		writel(0xffff, gp->regs + MAC_HASH13);
-		writel(0xffff, gp->regs + MAC_HASH14);
-		writel(0xffff, gp->regs + MAC_HASH15);
-	} else if (gp->dev->flags & IFF_PROMISC) {
-		u32 rxcfg = readl(gp->regs + MAC_RXCFG);
-		int limit = 10000;
-
-		writel(rxcfg & ~MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG);
-		while (readl(gp->regs + MAC_RXCFG) & MAC_RXCFG_ENAB) {
-			if (!limit--)
-				break;
-			udelay(10);
-		}
-
-		rxcfg |= MAC_RXCFG_PROM;
-		writel(rxcfg, gp->regs + MAC_RXCFG);
-	} else {
-		u16 hash_table[16];
-		u32 crc;
-		struct dev_mc_list *dmi = gp->dev->mc_list;
-		int i;
-
-		for (i = 0; i < 16; i++)
-			hash_table[i] = 0;
-
-		for (i = 0; i < dev->mc_count; i++) {
-			char *addrs = dmi->dmi_addr;
-
-			dmi = dmi->next;
+	rxcfg = readl(gp->regs + MAC_RXCFG);
+	rxcfg_new = gem_setup_multicast(gp);
+	
+	writel(rxcfg & ~MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG);
+	while (readl(gp->regs + MAC_RXCFG) & MAC_RXCFG_ENAB) {
+		if (!limit--)
+			break;
+		udelay(10);
+	}
 
-			if (!(*addrs & 1))
-				continue;
+	rxcfg &= ~(MAC_RXCFG_PROM | MAC_RXCFG_HFE);
+	rxcfg |= rxcfg_new;
 
-			crc = ether_crc_le(6, addrs);
-			crc >>= 24;
-			hash_table[crc >> 4] |= 1 << (crc & 0xf);
-		}
-		writel(hash_table[0], gp->regs + MAC_HASH0);
-		writel(hash_table[1], gp->regs + MAC_HASH1);
-		writel(hash_table[2], gp->regs + MAC_HASH2);
-		writel(hash_table[3], gp->regs + MAC_HASH3);
-		writel(hash_table[4], gp->regs + MAC_HASH4);
-		writel(hash_table[5], gp->regs + MAC_HASH5);
-		writel(hash_table[6], gp->regs + MAC_HASH6);
-		writel(hash_table[7], gp->regs + MAC_HASH7);
-		writel(hash_table[8], gp->regs + MAC_HASH8);
-		writel(hash_table[9], gp->regs + MAC_HASH9);
-		writel(hash_table[10], gp->regs + MAC_HASH10);
-		writel(hash_table[11], gp->regs + MAC_HASH11);
-		writel(hash_table[12], gp->regs + MAC_HASH12);
-		writel(hash_table[13], gp->regs + MAC_HASH13);
-		writel(hash_table[14], gp->regs + MAC_HASH14);
-		writel(hash_table[15], gp->regs + MAC_HASH15);
-	}
+	writel(rxcfg, gp->regs + MAC_RXCFG);
 
 	/* Hrm... we may walk on the reset task here... */
 	netif_wake_queue(dev);
@@ -2470,7 +2451,7 @@
 	case ETHTOOL_GMSGLVL: {
 		struct ethtool_value edata = { cmd: ETHTOOL_GMSGLVL };
 
-		edata.data = gem_debug;
+		edata.data = gp->msg_enable;
 		if (copy_to_user(ep_user, &edata, sizeof(edata)))
 			return -EFAULT;
 		return 0;
@@ -2482,7 +2463,7 @@
 
 		if (copy_from_user(&edata, ep_user, sizeof(edata)))
 			return -EFAULT;
-		gem_debug = edata.data;
+		gp->msg_enable = edata.data;
 		return 0;
 	}
 
@@ -2678,6 +2659,8 @@
 	dev->base_addr = (long) pdev;
 	gp->dev = dev;
 
+	gp->msg_enable = (gem_debug < 0 ? DEFAULT_MSG : gem_debug);
+
 	spin_lock_init(&gp->lock);
 	init_MUTEX(&gp->pm_sem);
 
@@ -2712,25 +2695,15 @@
 	 * not have properly shut down the PHY.
 	 */
 #ifdef CONFIG_ALL_PPC
-	if (pdev->vendor == PCI_VENDOR_ID_APPLE) {
+	if (pdev->vendor == PCI_VENDOR_ID_APPLE)
 		gem_apple_powerup(gp);
-		if (gem_check_invariants(gp))
-			goto err_out_iounmap;
-		gem_stop(gp);
-		gp->hw_running = 1;
-		gem_init_phy(gp);
-		gem_begin_auto_negotiation(gp, NULL);
-	}
 #endif
-	/* Non Apple hardware, we just reset the chip and check
-	 * for invariants
-	 */
-	if (pdev->vendor != PCI_VENDOR_ID_APPLE) {
-		gem_stop(gp);
-		if (gem_check_invariants(gp))
-			goto err_out_iounmap;
-		gp->hw_running = 1;
-	}
+	gem_stop(gp);
+	if (gem_check_invariants(gp))
+		goto err_out_iounmap;
+	gp->hw_running = 1;
+	gem_init_phy(gp);
+	gem_begin_auto_negotiation(gp, NULL);
 
 	/* It is guarenteed that the returned buffer will be at least
 	 * PAGE_SIZE aligned.
@@ -2838,7 +2811,7 @@
 	name:		GEM_MODULE_NAME,
 	id_table:	gem_pci_tbl,
 	probe:		gem_init_one,
-	remove:		__devexit_p(gem_remove_one),
+	remove:		gem_remove_one,
 #ifdef CONFIG_PM
 	suspend:	gem_suspend,
 	resume:		gem_resume,
diff -u --recursive --new-file v2.5.2/linux/drivers/net/sungem.h linux/drivers/net/sungem.h
--- v2.5.2/linux/drivers/net/sungem.h	Mon Jan 14 18:25:09 2002
+++ linux/drivers/net/sungem.h	Tue Jan 15 10:52:11 2002
@@ -1,4 +1,4 @@
-/* $Id: sungem.h,v 1.10 2001/11/29 03:57:33 davem Exp $
+/* $Id: sungem.h,v 1.11 2002/01/12 07:19:55 davem Exp $
  * sungem.h: Definitions for Sun GEM ethernet driver.
  *
  * Copyright (C) 2000 David S. Miller (davem@redhat.com)
@@ -972,6 +972,8 @@
 	struct sk_buff *rx_skbs[RX_RING_SIZE];
 	struct sk_buff *tx_skbs[RX_RING_SIZE];
 
+	u32			msg_enable;
+
 	struct net_device_stats net_stats;
 
 	enum gem_phy_type	phy_type;
@@ -995,8 +997,8 @@
 	volatile int		reset_task_pending;
 	
 	/* Diagnostic counters and state. */
-	u64 pause_entered;
-	u16 pause_last_time_recvd;
+	u64			pause_entered;
+	u16			pause_last_time_recvd;
 
 	dma_addr_t gblock_dvma;
 	struct pci_dev *pdev;
diff -u --recursive --new-file v2.5.2/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c
--- v2.5.2/linux/drivers/net/sunhme.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/net/sunhme.c	Tue Jan 15 10:52:11 2002
@@ -1,4 +1,4 @@
-/* $Id: sunhme.c,v 1.123 2001/10/02 02:22:30 davem Exp $
+/* $Id: sunhme.c,v 1.124 2002/01/15 06:25:51 davem Exp $
  * sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching,
  *           auto carrier detecting ethernet driver.  Also known as the
  *           "Happy Meal Ethernet" found on SunSwift SBUS cards.
diff -u --recursive --new-file v2.5.2/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c
--- v2.5.2/linux/drivers/net/sunlance.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/net/sunlance.c	Tue Jan 15 10:52:11 2002
@@ -1,4 +1,4 @@
-/* $Id: sunlance.c,v 1.109 2001/10/21 06:35:29 davem Exp $
+/* $Id: sunlance.c,v 1.112 2002/01/15 06:48:55 davem Exp $
  * lance.c: Linux/Sparc/Lance driver
  *
  *	Written 1995, 1996 by Miguel de Icaza
@@ -924,14 +924,14 @@
 
 	last_dev = dev;
 
+	STOP_LANCE(lp);
+
 	if (request_irq(dev->irq, &lance_interrupt, SA_SHIRQ,
 			lancestr, (void *) dev)) {
 		printk(KERN_ERR "Lance: Can't get irq %s\n", __irq_itoa(dev->irq));
 		return -EAGAIN;
 	}
 
-	STOP_LANCE(lp);
-
 	/* On the 4m, setup the ledma to provide the upper bits for buffers */
 	if (lp->dregs) {
 		u32 regval = lp->init_block_dvma & 0xff000000;
@@ -1181,7 +1181,7 @@
 	volatile u16 *mcast_table = (u16 *) &ib->filter;
 	struct dev_mc_list *dmi = dev->mc_list;
 	char *addrs;
-	int i, j, bit, byte;
+	int i;
 	u32 crc;
 	
 	/* set all multicast bits */
diff -u --recursive --new-file v2.5.2/linux/drivers/net/sunqe.c linux/drivers/net/sunqe.c
--- v2.5.2/linux/drivers/net/sunqe.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/net/sunqe.c	Tue Jan 15 10:52:11 2002
@@ -1,4 +1,4 @@
-/* $Id: sunqe.c,v 1.53 2001/12/21 00:54:31 davem Exp $
+/* $Id: sunqe.c,v 1.55 2002/01/15 06:48:55 davem Exp $
  * sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver.
  *          Once again I am out to prove that every ethernet
  *          controller out there can be most efficiently programmed
@@ -629,7 +629,7 @@
 	struct dev_mc_list *dmi = dev->mc_list;
 	u8 new_mconfig = qep->mconfig;
 	char *addrs;
-	int i, j, bit, byte;
+	int i;
 	u32 crc;
 
 	/* Lock out others. */
diff -u --recursive --new-file v2.5.2/linux/drivers/parport/ChangeLog linux/drivers/parport/ChangeLog
--- v2.5.2/linux/drivers/parport/ChangeLog	Mon Nov 12 09:45:32 2001
+++ linux/drivers/parport/ChangeLog	Thu Jan 17 14:07:57 2002
@@ -1,3 +1,29 @@
+2001-12-07  Tim Waugh  <twaugh@redhat.com>
+
+	* ieee1284_ops.c (parport_ieee1284_epp_write_addr,
+	parport_ieee1284_epp_read_addr): Actually do something useful.
+
+2001-12-07  Tim Waugh  <twaugh@redhat.com>
+
+	* parport_pc.c (dmaval): Don't use DMA by default.  It seems to be
+	too buggy at the moment.  Use 'dma=auto' to restore the previous
+	behaviour.
+
+2001-12-03  Rich Liu  <Rich.Liu@ite.com.tw>
+
+	* parport_pc.c (sio_ite_8872_probe): ITE8873 is a single-port
+	serial board, not a serial+parallel.
+
+2001-11-30  Niels Kristian Bech Jensen  <nkbj@image.dk>
+
+	* parport_pc.c: Fix compiler warning.
+
+2001-12-06  Tim Waugh  <twaugh@redhat.com>
+
+	* ieee1284_ops.c (parport_ieee1284_ecp_read_data): Mask off
+	PARPORT_CONTROL_AUTOFD as well.  Bug spotted by Joe
+	<joeja@mindspring.com>.
+
 2001-11-12  Tim Waugh  <twaugh@redhat.com>
 
 	* parport_pc.c (init_module): Warn when parameters are ignored.
diff -u --recursive --new-file v2.5.2/linux/drivers/parport/Config.in linux/drivers/parport/Config.in
--- v2.5.2/linux/drivers/parport/Config.in	Sun Nov 11 10:09:33 2001
+++ linux/drivers/parport/Config.in	Tue Jan 15 10:58:04 2002
@@ -24,9 +24,13 @@
          bool '    Use FIFO/DMA if available (EXPERIMENTAL)' CONFIG_PARPORT_PC_FIFO
          bool '    SuperIO chipset support (EXPERIMENTAL)' CONFIG_PARPORT_PC_SUPERIO
       fi
-   fi
-   if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
-	 dep_tristate '    Support for PCMCIA management for PC-style ports' CONFIG_PARPORT_PC_PCMCIA $CONFIG_PCMCIA
+      if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
+         if [ "$CONFIG_PARPORT_PC" = "y" ]; then
+            dep_tristate '    Support for PCMCIA management for PC-style ports' CONFIG_PARPORT_PC_PCMCIA $CONFIG_PCMCIA
+         else
+            dep_tristate '    Support for PCMCIA management for PC-style ports' CONFIG_PARPORT_PC_PCMCIA $CONFIG_PARPORT_PC
+         fi
+      fi
    fi
    if [ "$CONFIG_ARM" = "y" ]; then
       dep_tristate '  Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT
diff -u --recursive --new-file v2.5.2/linux/drivers/parport/ieee1284.c linux/drivers/parport/ieee1284.c
--- v2.5.2/linux/drivers/parport/ieee1284.c	Thu Oct 25 00:07:39 2001
+++ linux/drivers/parport/ieee1284.c	Tue Jan 15 13:53:51 2002
@@ -128,7 +128,7 @@
 			return 0;
 		if (signal_pending (current))
 			return -EINTR;
-		if (current->need_resched)
+		if (need_resched())
 			break;
 		if (i >= 2)
 			udelay (5);
diff -u --recursive --new-file v2.5.2/linux/drivers/parport/ieee1284_ops.c linux/drivers/parport/ieee1284_ops.c
--- v2.5.2/linux/drivers/parport/ieee1284_ops.c	Thu Oct 25 00:07:39 2001
+++ linux/drivers/parport/ieee1284_ops.c	Thu Jan 17 14:07:57 2002
@@ -136,7 +136,7 @@
                 /* Let another process run if it needs to. */
 		if (time_before (jiffies, expire))
 			if (!parport_yield_blocking (dev)
-			    && current->need_resched)
+			    && need_resched())
 				schedule ();
 	}
  stop:
@@ -514,7 +514,8 @@
 
 	/* Set HostAck low to start accepting data. */
 	ctl = parport_read_control (port);
-	ctl &= ~(PARPORT_CONTROL_STROBE | PARPORT_CONTROL_INIT);
+	ctl &= ~(PARPORT_CONTROL_STROBE | PARPORT_CONTROL_INIT |
+		 PARPORT_CONTROL_AUTOFD);
 	parport_write_control (port,
 			       ctl | PARPORT_CONTROL_AUTOFD);
 	while (count < len) {
@@ -823,35 +824,40 @@
 					const void *buffer, size_t len,
 					int flags)
 {
-	/* This is untested */
 	unsigned char *bp = (unsigned char *) buffer;
 	size_t ret = 0;
 
+	/* set EPP idle state (just to make sure) with strobe low */
 	parport_frob_control (port,
 			      PARPORT_CONTROL_STROBE |
+			      PARPORT_CONTROL_AUTOFD |
 			      PARPORT_CONTROL_SELECT |
-			      PARPORT_CONTROL_AUTOFD,
+			      PARPORT_CONTROL_INIT,
 			      PARPORT_CONTROL_STROBE |
-			      PARPORT_CONTROL_SELECT);
+			      PARPORT_CONTROL_INIT);
 	port->ops->data_forward (port);
 	for (; len > 0; len--, bp++) {
-		/* Write data and assert nAStrb. */
+		/* Event 56: Write data and set nAStrb low. */
 		parport_write_data (port, *bp);
 		parport_frob_control (port, PARPORT_CONTROL_SELECT,
 				      PARPORT_CONTROL_SELECT);
 
-		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY,
-					     PARPORT_STATUS_BUSY, 10))
+		/* Event 58: wait for busy (nWait) to go high */
+		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 10))
 			break;
 
+		/* Event 59: set nAStrb high */
 		parport_frob_control (port, PARPORT_CONTROL_SELECT, 0);
 
-		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 5))
+		/* Event 60: wait for busy (nWait) to go low */
+		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY,
+					     PARPORT_STATUS_BUSY, 5))
 			break;
 
 		ret++;
 	}
 
+	/* Event 61: set strobe (nWrite) high */
 	parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
 
 	return ret;
@@ -862,28 +868,36 @@
 				       void *buffer, size_t len,
 				       int flags)
 {
-	/* This is untested. */
 	unsigned char *bp = (unsigned char *) buffer;
 	unsigned ret = 0;
 
+	/* Set EPP idle state (just to make sure) with strobe high */
 	parport_frob_control (port,
 			      PARPORT_CONTROL_STROBE |
-			      PARPORT_CONTROL_AUTOFD, 0);
+			      PARPORT_CONTROL_AUTOFD |
+			      PARPORT_CONTROL_SELECT |
+			      PARPORT_CONTROL_INIT,
+			      PARPORT_CONTROL_INIT);
 	port->ops->data_reverse (port);
 	for (; len > 0; len--, bp++) {
-		parport_frob_control (port, PARPORT_CONTROL_SELECT, 0);
+		/* Event 64: set nSelectIn (nAStrb) low */
+		parport_frob_control (port, PARPORT_CONTROL_SELECT,
+				      PARPORT_CONTROL_SELECT);
 
-		/* Event 58 */
-		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY,
-					     PARPORT_STATUS_BUSY, 10))
+		/* Event 58: wait for Busy to go high */
+		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) {
 			break;
+		}
 
 		*bp = parport_read_data (port);
 
+		/* Event 59: set nSelectIn (nAStrb) high */
 		parport_frob_control (port, PARPORT_CONTROL_SELECT,
 				      PARPORT_CONTROL_SELECT);
 
-		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 5))
+		/* Event 60: wait for Busy to go low */
+		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 
+					     PARPORT_STATUS_BUSY, 5))
 			break;
 
 		ret++;
diff -u --recursive --new-file v2.5.2/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c
--- v2.5.2/linux/drivers/parport/parport_pc.c	Mon Nov 12 09:44:58 2001
+++ linux/drivers/parport/parport_pc.c	Thu Jan 17 14:07:57 2002
@@ -91,7 +91,9 @@
 } superios[NR_SUPERIOS] __devinitdata = { {0,},};
 
 static int user_specified __devinitdata = 0;
+#if defined(CONFIG_PARPORT_PC_FIFO) || defined(CONFIG_PARPORT_PC_SUPERIO)
 static int verbose_probing;
+#endif
 static int registered_parport;
 
 /* frob_control, but for ECR */
@@ -596,7 +598,7 @@
 		unsigned char ecrval = inb (ECONTROL (port));
 		int i = 0;
 
-		if (current->need_resched && time_before (jiffies, expire))
+		if (need_resched() && time_before (jiffies, expire))
 			/* Can't yield the port. */
 			schedule ();
 
@@ -622,7 +624,7 @@
 			}
 			ecrval = inb (ECONTROL (port));
 			if (!(ecrval & (1<<2))) {
-				if (current->need_resched &&
+				if (need_resched() &&
 				    time_before (jiffies, expire))
 					schedule ();
 
@@ -746,8 +748,7 @@
 		}
 		/* Is serviceIntr set? */
 		if (!(inb (ECONTROL (port)) & (1<<2))) {
-			if (current->need_resched)
-				schedule ();
+			cond_resched();
 
 			goto false_alarm;
 		}
@@ -758,9 +759,7 @@
 		count = get_dma_residue(port->dma);
 		release_dma_lock(dmaflag);
 
-		if (current->need_resched)
-			/* Can't yield the port. */
-			schedule ();
+		cond_resched(); /* Can't yield the port. */
 
 		/* Anyone else waiting for the port? */
 		if (port->waithead) {
@@ -1093,7 +1092,7 @@
 		long int expire = jiffies + port->cad->timeout;
 		unsigned char ecrval = inb (ECONTROL (port));
 
-		if (current->need_resched && time_before (jiffies, expire))
+		if (need_resched() && time_before (jiffies, expire))
 			/* Can't yield the port. */
 			schedule ();
 
@@ -1130,7 +1129,7 @@
 			}
 			ecrval = inb (ECONTROL (port));
 			if (!(ecrval & (1<<2))) {
-				if (current->need_resched &&
+				if (need_resched() &&
 				    time_before (jiffies, expire)) {
 					schedule ();
 				}
@@ -1780,6 +1779,7 @@
 	return ok;
 }
 
+#ifdef CONFIG_PARPORT_PC_FIFO
 static int __devinit parport_ECP_supported(struct parport *pb)
 {
 	int i;
@@ -1905,6 +1905,7 @@
 
 	return 1;
 }
+#endif
 
 static int __devinit parport_ECPPS2_supported(struct parport *pb)
 {
@@ -2004,7 +2005,9 @@
 
 /* Don't bother probing for modes we know we won't use. */
 static int __devinit parport_PS2_supported(struct parport *pb) { return 0; }
+#ifdef CONFIG_PARPORT_PC_FIFO
 static int __devinit parport_ECP_supported(struct parport *pb) { return 0; }
+#endif
 static int __devinit parport_EPP_supported(struct parport *pb) { return 0; }
 static int __devinit parport_ECPEPP_supported(struct parport *pb){return 0;}
 static int __devinit parport_ECPPS2_supported(struct parport *pb){return 0;}
@@ -2453,9 +2456,8 @@
 		ite8872set = 0x64e00000;
 		break;
 	case 0x6:
-		printk (KERN_INFO "parport_pc: ITE8873 found (1S1P)\n");
-		ite8872set = 0x64a00000;
-		break;
+		printk (KERN_INFO "parport_pc: ITE8873 found (1S)\n");
+		return 0;
 	case 0x8:
 		DPRINTK (KERN_DEBUG "parport_pc: ITE8874 found (2S)\n");
 		return 0;
@@ -3007,7 +3009,7 @@
 static int io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 };
 static int io_hi[PARPORT_PC_MAX_PORTS+1] =
 	{ [0 ... PARPORT_PC_MAX_PORTS] = PARPORT_IOHI_AUTO };
-static int dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_AUTO };
+static int dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_NONE };
 static int irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY };
 static const char *irq[PARPORT_PC_MAX_PORTS] = { NULL, };
 static const char *dma[PARPORT_PC_MAX_PORTS] = { NULL, };
@@ -3024,8 +3026,10 @@
 MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
 MODULE_PARM_DESC(dma, "DMA channel");
 MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
-MODULE_PARM(verbose_probing, "i");
+#if defined(CONFIG_PARPORT_PC_FIFO) || defined(CONFIG_PARPORT_PC_SUPERIO)
 MODULE_PARM_DESC(verbose_probing, "Log chit-chat during initialisation");
+MODULE_PARM(verbose_probing, "i");
+#endif
 
 int init_module(void)
 {	
diff -u --recursive --new-file v2.5.2/linux/drivers/pcmcia/hd64465_ss.c linux/drivers/pcmcia/hd64465_ss.c
--- v2.5.2/linux/drivers/pcmcia/hd64465_ss.c	Tue Jul 10 20:16:30 2001
+++ linux/drivers/pcmcia/hd64465_ss.c	Tue Jan 15 10:56:35 2002
@@ -673,6 +673,10 @@
 	     */
 	    DPRINTK("remap_page_range(vaddr=0x%08lx, paddr=0x%08lx, size=0x%08lxx)\n",
 	    	vaddrbase + pstart, paddrbase + pstart, psize);
+#error This does not work.  Firstly remap_page_range() uses current->mm for
+#error the address space, which is wrong for kernel mappings.  remap_page_range
+#error also does flush_{cache,tlb}_range() which ONLY works for user mappings.
+#error Next, remap_page_range() now wants to take a vm_area_struct arg.
 	    remap_page_range(vaddrbase + pstart, paddrbase + pstart, psize, prot);
 	    
 	    /*
diff -u --recursive --new-file v2.5.2/linux/drivers/sbus/char/envctrl.c linux/drivers/sbus/char/envctrl.c
--- v2.5.2/linux/drivers/sbus/char/envctrl.c	Wed Oct 10 23:42:47 2001
+++ linux/drivers/sbus/char/envctrl.c	Tue Jan 15 10:52:11 2002
@@ -1,4 +1,4 @@
-/* $Id: envctrl.c,v 1.24 2001/10/08 22:19:51 davem Exp $
+/* $Id: envctrl.c,v 1.25 2002/01/15 09:01:26 davem Exp $
  * envctrl.c: Temperature and Fan monitoring on Machines providing it.
  *
  * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
@@ -776,24 +776,19 @@
 static void envctrl_init_adc(struct i2c_child_t *pchild, int node)
 {
 	char chnls_desc[CHANNEL_DESC_SZ];
-	int i, len, j = 0;
-	char *ptr;
+	int i = 0, len;
+	char *pos = chnls_desc;
 
-	/* Firmware describe channels into a stream separated by a '\0'.
-	 * Replace all '\0' with a space.
-	 */
-        len = prom_getproperty(node, "channels-description", chnls_desc,
+	/* Firmware describe channels into a stream separated by a '\0'. */
+	len = prom_getproperty(node, "channels-description", chnls_desc,
 			       CHANNEL_DESC_SZ);
-        for (i = 0; i < len; i++) {
-                if (chnls_desc[i] == '\0')
-                        chnls_desc[i] = ' ';
-        }
-
-	ptr = strtok(chnls_desc, " ");
-	while (ptr != NULL) {
-		envctrl_set_mon(pchild, ptr, j);
-		ptr = strtok(NULL, " ");
-		j++;
+	chnls_desc[CHANNEL_DESC_SZ - 1] = '\0';
+
+	while (len > 0) {
+		int l = strlen(pos) + 1;
+		envctrl_set_mon(pchild, pos, i++);
+		len -= l;
+		pos += l;
 	}
 
 	/* Get optional properties. */
diff -u --recursive --new-file v2.5.2/linux/drivers/sbus/char/flash.c linux/drivers/sbus/char/flash.c
--- v2.5.2/linux/drivers/sbus/char/flash.c	Wed Oct 10 23:42:47 2001
+++ linux/drivers/sbus/char/flash.c	Tue Jan 15 10:56:35 2002
@@ -1,4 +1,4 @@
-/* $Id: flash.c,v 1.24 2001/10/08 22:19:51 davem Exp $
+/* $Id: flash.c,v 1.25 2001/12/21 04:56:16 davem Exp $
  * flash.c: Allow mmap access to the OBP Flash, for OBP updates.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -74,7 +74,7 @@
 	pgprot_val(vma->vm_page_prot) |= _PAGE_E;
 	vma->vm_flags |= (VM_SHM | VM_LOCKED);
 
-	if (remap_page_range(vma->vm_start, addr, size, vma->vm_page_prot))
+	if (remap_page_range(vma, vma->vm_start, addr, size, vma->vm_page_prot))
 		return -EAGAIN;
 		
 	return 0;
diff -u --recursive --new-file v2.5.2/linux/drivers/sbus/char/vfc_dev.c linux/drivers/sbus/char/vfc_dev.c
--- v2.5.2/linux/drivers/sbus/char/vfc_dev.c	Sun Aug 12 10:38:48 2001
+++ linux/drivers/sbus/char/vfc_dev.c	Tue Jan 15 10:56:35 2002
@@ -632,7 +632,7 @@
 	vma->vm_flags |=
 		(VM_SHM | VM_LOCKED | VM_IO | VM_MAYREAD | VM_MAYWRITE | VM_MAYSHARE);
 	map_offset = (unsigned int) (long)dev->phys_regs;
-	ret = io_remap_page_range(vma->vm_start, map_offset, map_size, 
+	ret = io_remap_page_range(vma, vma->vm_start, map_offset, map_size, 
 				  vma->vm_page_prot, dev->which_io);
 
 	if(ret)
diff -u --recursive --new-file v2.5.2/linux/drivers/sbus/char/zs.c linux/drivers/sbus/char/zs.c
--- v2.5.2/linux/drivers/sbus/char/zs.c	Mon Jan 14 18:25:09 2002
+++ linux/drivers/sbus/char/zs.c	Tue Jan 15 10:52:11 2002
@@ -1,4 +1,4 @@
-/* $Id: zs.c,v 1.70 2002/01/08 16:00:16 davem Exp $
+/* $Id: zs.c,v 1.71 2002/01/12 07:04:54 davem Exp $
  * zs.c: Zilog serial port driver for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -7,6 +7,10 @@
  *
  * Fixed to use tty_get_baud_rate().
  *   Theodore Ts'o <tytso@mit.edu>, 2001-Oct-12
+ *
+ * /proc/tty/driver/serial now exists and is readable.
+ *   Alex Buell <alex.buell@tahallah.demon.co.uk>, 2001-12-23
+ *
  */
 
 #include <linux/errno.h>
@@ -1653,6 +1657,81 @@
 }
 
 /*
+ *
+ * line_info - returns information about each channel
+ *
+ */
+static inline int line_info(char *buf, struct sun_serial *info)
+{
+	unsigned char status;
+	char stat_buf[30];
+	int ret;
+
+	ret = sprintf(buf, "%d: uart:Zilog8530 port:%x irq:%d",
+		info->line, info->port, info->irq);
+
+	cli();
+	status = sbus_readb(&info->zs_channel->control);
+	ZSDELAY();
+	ZSLOG(REGCTRL, status, 0);
+	sti();
+
+	stat_buf[0] = 0;
+	stat_buf[1] = 0;
+	if (info->curregs[5] & RTS)
+		strcat(stat_buf, "|RTS");
+	if (status & CTS)
+		strcat(stat_buf, "|CTS");
+	if (info->curregs[5] & DTR)
+		strcat(stat_buf, "|DTR");
+	if (status & SYNC)
+		strcat(stat_buf, "|DSR");
+	if (status & DCD)
+		strcat(stat_buf, "|CD");
+
+	ret += sprintf(buf + ret, " baud:%d %s\n", info->zs_baud, stat_buf + 1);
+	return ret;
+}
+
+/*
+ *
+ * zs_read_proc() - called when /proc/tty/driver/serial is read.
+ *
+ */
+int zs_read_proc(char *page, char **start, off_t off, int count,
+                 int *eof, void *data)
+{
+	char *revision = "$Revision: 1.71 $";
+	char *version, *p;
+	int i, len = 0, l;
+	off_t begin = 0;
+
+	version = strchr(revision, ' ');
+	p = strchr(++version, ' ');
+	*p = '\0';
+	len += sprintf(page, "serinfo:1.0 driver:%s\n", version);
+	*p = ' ';
+
+	for (i = 0; i < NUM_CHANNELS && len < 4000; i++) {
+		l = line_info(page + len, &zs_soft[i]);
+		len += l;
+		if (len+begin > off+count)
+			goto done;
+		if (len+begin < off) {
+			begin += len;
+			len = 0;
+		}
+	}
+
+	*eof = 1;
+done:
+	if (off >= len+begin)
+		return 0;
+	*start = page + (off-begin);
+	return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+/*
  * ------------------------------------------------------------
  * zs_open() and friends
  * ------------------------------------------------------------
@@ -1887,7 +1966,7 @@
 
 static void show_serial_version(void)
 {
-	char *revision = "$Revision: 1.70 $";
+	char *revision = "$Revision: 1.71 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
@@ -2398,8 +2477,8 @@
 	serial_driver.hangup = zs_hangup;
 
 	/* I'm too lazy, someone write versions of this for us. -DaveM */
-	serial_driver.read_proc = 0;
-	serial_driver.proc_entry = 0;
+	/* I just did. :-) -AIB 2001-12-23 */
+	serial_driver.read_proc = zs_read_proc;
 
 	/*
 	 * The callout device is just like normal device except for
@@ -2409,6 +2488,8 @@
 	callout_driver.name = "cua/%d";
 	callout_driver.major = TTYAUX_MAJOR;
 	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+	callout_driver.read_proc = 0;
+	callout_driver.proc_entry = 0;
 
 	if (tty_register_driver(&serial_driver))
 		panic("Couldn't register serial driver\n");
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c
--- v2.5.2/linux/drivers/scsi/advansys.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/advansys.c	Thu Jan 17 13:59:33 2002
@@ -1,4 +1,4 @@
-#define ASC_VERSION "3.3G"    /* AdvanSys Driver Version */
+#define ASC_VERSION "3.3GG"    /* AdvanSys Driver Version */
 
 /*
  * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
@@ -670,6 +670,9 @@
          1. Return an error from narrow boards if passed a 16 byte
             CDB. The wide board can already handle 16 byte CDBs.
 
+     3.3GG (01/02/02):
+	 1. hacks for lk 2.5 series (D. Gilbert)
+
   I. Known Problems/Fix List (XXX)
 
      1. Need to add memory mapping workaround. Test the memory mapping.
@@ -3610,6 +3613,23 @@
 #define ASC_MIN(a, b) (((a) < (b)) ? (a) : (b))
 #endif /* CONFIG_PROC_FS */
 
+/*
+ * XXX - Release and acquire the io_request_lock. These macros are needed
+ * because the 2.4 kernel SCSI mid-level driver holds the 'io_request_lock'
+ * on entry to SCSI low-level drivers.
+ *
+ * These definitions and all code that uses code should be removed when the
+ * SCSI mid-level driver no longer holds the 'io_request_lock' on entry to
+ * SCSI low-level driver detect, queuecommand, and reset entrypoints.
+ *
+ * The interrupt flags values doesn't matter in the macros because the
+ * SCSI mid-level will save and restore the flags values before and after
+ * calling advansys_detect, advansys_queuecommand, and advansys_reset where
+ * these macros are used. We do want interrupts enabled after the lock is
+ * released so an explicit sti() is done. The driver only needs interrupts
+ * disabled when it acquires the per board lock.
+ */
+
 /* Asc Library return codes */
 #define ASC_TRUE        1
 #define ASC_FALSE       0
@@ -4054,6 +4074,7 @@
         ADVEEP_38C1600_CONFIG adv_38C1600_eep;  /* 38C1600 EEPROM config. */
     } eep_config;
     ulong                last_reset;            /* Saved last reset time */
+    spinlock_t lock;                            /* Board spinlock */
 #ifdef CONFIG_PROC_FS
     /* /proc/scsi/advansys/[0...] */
     char                 *prtbuf;               /* /proc print buffer */
@@ -4206,7 +4227,7 @@
 STATIC void       advansys_interrupt(int, void *, struct pt_regs *);
 STATIC void       advansys_select_queue_depths(struct Scsi_Host *,
                                                Scsi_Device *);
-STATIC void       asc_scsi_done_list(Scsi_Cmnd *);
+STATIC void       asc_scsi_done_list(Scsi_Cmnd *, int from_isr);
 STATIC int        asc_execute_scsi_cmnd(Scsi_Cmnd *);
 STATIC int        asc_build_req(asc_board_t *, Scsi_Cmnd *);
 STATIC int        adv_build_req(asc_board_t *, Scsi_Cmnd *, ADV_SCSI_REQ_Q **);
@@ -4799,6 +4820,9 @@
             memset(boardp, 0, sizeof(asc_board_t));
             boardp->id = asc_board_count - 1;
 
+            /* Initialize spinlock. */
+            boardp->lock = SPIN_LOCK_UNLOCKED; /* replaced by host_lock dpg */
+
             /*
              * Handle both narrow and wide boards.
              *
@@ -5511,7 +5535,7 @@
                 }
             } else {
                 ADV_CARR_T      *carrp;
-                int             req_cnt;
+                int             req_cnt = 0;
                 adv_req_t       *reqp = NULL;
                 int             sg_cnt = 0;
 
@@ -5845,7 +5869,9 @@
     boardp = ASC_BOARDP(shp);
     ASC_STATS(shp, queuecommand);
 
-    spin_lock_irqsave(&shp->host_lock, flags);
+    /* host_lock taken by mid-level prior to call but need to protect */
+    /* against own ISR */
+    spin_lock_irqsave(&boardp->lock, flags);
 
     /*
      * Block new commands while handling a reset or abort request.
@@ -5862,7 +5888,7 @@
          * handling.
          */
         asc_enqueue(&boardp->done, scp, ASC_BACK);
-        spin_unlock_irqrestore(&shp->host_lock, flags);
+	spin_unlock_irqrestore(&boardp->lock, flags);
         return 0;
     }
 
@@ -5902,11 +5928,11 @@
     default:
         done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
         /* Interrupts could be enabled here. */
-        asc_scsi_done_list(done_scp);
+        asc_scsi_done_list(done_scp, 0);
         break;
     }
+    spin_unlock_irqrestore(&boardp->lock, flags);
 
-    spin_unlock_irqrestore(&shp->host_lock, flags);
     return 0;
 }
 
@@ -5952,13 +5978,13 @@
     /*
      * Check for re-entrancy.
      */
-    spin_lock_irqsave(&shp->host_lock, flags);
+    spin_lock_irqsave(&boardp->lock, flags);
     if (boardp->flags & ASC_HOST_IN_RESET) {
-        spin_unlock_irqrestore(&shp->host_lock, flags);
+	spin_unlock_irqrestore(&boardp->lock, flags);
         return FAILED;
     }
     boardp->flags |= ASC_HOST_IN_RESET;
-    spin_unlock_irqrestore(&shp->host_lock, flags);
+    spin_unlock_irqrestore(&boardp->lock, flags);
 
     if (ASC_NARROW_BOARD(boardp)) {
         /*
@@ -5989,11 +6015,7 @@
         }
 
         ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
-
-        /*
-         * Acquire the board lock.
-         */
-        spin_lock_irqsave(&shp->host_lock, flags);
+	spin_lock_irqsave(&boardp->lock, flags);
 
     } else {
         /*
@@ -6020,14 +6042,9 @@
             ret = FAILED;
             break;
         }
-        /*
-         * Acquire the board lock and ensure all requests completed by the
-         * microcode have been processed by calling AdvISR().
-         */
-        spin_lock_irqsave(&shp->host_lock, flags);
+	spin_lock_irqsave(&boardp->lock, flags);
         (void) AdvISR(adv_dvc_varp);
     }
-
     /* Board lock is held. */
 
     /*
@@ -6088,15 +6105,13 @@
 
     /* Clear reset flag. */
     boardp->flags &= ~ASC_HOST_IN_RESET;
-
-    /* Release the board. */
-    spin_unlock_irqrestore(&shp->host_lock, flags);
+    spin_unlock_irqrestore(&boardp->lock, flags);
 
     /*
      * Complete all the 'done_scp' requests.
      */
     if (done_scp != NULL) {
-        asc_scsi_done_list(done_scp);
+        asc_scsi_done_list(done_scp, 0);
     }
 
     ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
@@ -6259,6 +6274,7 @@
     asc_board_t     *boardp;
     Scsi_Cmnd       *done_scp = NULL, *last_scp = NULL;
     Scsi_Cmnd       *new_last_scp;
+    struct Scsi_Host *shp;
 
     ASC_DBG(1, "advansys_interrupt: begin\n");
 
@@ -6267,17 +6283,17 @@
      * AscISR() will call asc_isr_callback().
      */
     for (i = 0; i < asc_board_count; i++) {
-	struct Scsi_Host *shp = asc_host[i];
+	shp = asc_host[i];
         boardp = ASC_BOARDP(shp);
         ASC_DBG2(2, "advansys_interrupt: i %d, boardp 0x%lx\n",
             i, (ulong) boardp);
-        spin_lock_irqsave(&shp->host_lock, flags);
+        spin_lock_irqsave(&boardp->lock, flags);
         if (ASC_NARROW_BOARD(boardp)) {
             /*
              * Narrow Board
              */
-            if (AscIsIntPending(asc_host[i]->io_port)) {
-                ASC_STATS(asc_host[i], interrupt);
+            if (AscIsIntPending(shp->io_port)) {
+                ASC_STATS(shp, interrupt);
                 ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
                 AscISR(&boardp->dvc_var.asc_dvc_var);
             }
@@ -6287,7 +6303,7 @@
              */
             ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
             if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
-                ASC_STATS(asc_host[i], interrupt);
+                ASC_STATS(shp, interrupt);
             }
         }
 
@@ -6327,7 +6343,7 @@
                 }
             }
         }
-        spin_unlock_irqrestore(&shp->host_lock, flags);
+        spin_unlock_irqrestore(&boardp->lock, flags);
     }
 
     /*
@@ -6336,7 +6352,8 @@
      *
      * Complete all requests on the done list.
      */
-    asc_scsi_done_list(done_scp);
+
+    asc_scsi_done_list(done_scp, 1);
 
     ASC_DBG(1, "advansys_interrupt: end\n");
     return;
@@ -6383,9 +6400,10 @@
  * Interrupts can be enabled on entry.
  */
 STATIC void
-asc_scsi_done_list(Scsi_Cmnd *scp)
+asc_scsi_done_list(Scsi_Cmnd *scp, int from_isr)
 {
     Scsi_Cmnd    *tscp;
+    ulong	  flags = 0;
 
     ASC_DBG(2, "asc_scsi_done_list: begin\n");
     while (scp != NULL) {
@@ -6394,7 +6412,11 @@
         REQPNEXT(scp) = NULL;
         ASC_STATS(scp->host, done);
         ASC_ASSERT(scp->scsi_done != NULL);
+	if (from_isr)
+	    spin_lock_irqsave(&scp->host->host_lock, flags);
         scp->scsi_done(scp);
+	if (from_isr)
+	    spin_unlock_irqrestore(&scp->host->host_lock, flags);
         scp = tscp;
     }
     ASC_DBG(2, "asc_scsi_done_list: done\n");
@@ -6728,7 +6750,9 @@
         slp = (struct scatterlist *) scp->request_buffer;
         for (sgcnt = 0; sgcnt < scp->use_sg; sgcnt++, slp++) {
             asc_sg_head.sg_list[sgcnt].addr =
-                cpu_to_le32(virt_to_bus(slp->address));
+                cpu_to_le32(virt_to_bus(slp->address ? 
+		(unsigned char *)slp->address :
+		(unsigned char *)page_address(slp->page) + slp->offset));
             asc_sg_head.sg_list[sgcnt].bytes = cpu_to_le32(slp->length);
             ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512));
         }
@@ -6986,7 +7010,9 @@
         for (i = 0; i < NO_OF_SG_PER_BLOCK; i++)
         {
             sg_block->sg_list[i].sg_addr =
-                cpu_to_le32(virt_to_bus(slp->address));
+                cpu_to_le32(virt_to_bus(slp->address ? 
+		(unsigned char *)slp->address :
+                (unsigned char *)page_address(slp->page) + slp->offset));
             sg_block->sg_list[i].sg_count = cpu_to_le32(slp->length);
             ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512));
 
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c linux/drivers/scsi/aic7xxx/aic7xxx_linux.c
--- v2.5.2/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/aic7xxx/aic7xxx_linux.c	Thu Jan 17 13:59:33 2002
@@ -1700,6 +1700,7 @@
 			       cmd->request_buffer,
 			       cmd->request_bufflen,
 			       scsi_to_pci_dma_dir(cmd->sc_data_direction));
+			scb->sg_count = 0;
 			scb->sg_count = ahc_linux_map_seg(ahc, scb,
 							  sg, addr,
 							  cmd->request_bufflen);
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/aic7xxx_old.c linux/drivers/scsi/aic7xxx_old.c
--- v2.5.2/linux/drivers/scsi/aic7xxx_old.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/aic7xxx_old.c	Tue Jan 15 10:52:11 2002
@@ -4127,7 +4127,7 @@
   unsigned long cpu_flags = 0;
   struct aic7xxx_scb *scb;
 
-  spin_lock_irqsave(&p->host->host_lock, cpu_flags);
+  spin_lock_irqsave(p->host->host_lock, cpu_flags);
   p->dev_timer_active &= ~(0x01 << MAX_TARGETS);
   if ( (p->dev_timer_active & (0x01 << p->scsi_id)) &&
        time_after_eq(jiffies, p->dev_expires[p->scsi_id]) )
@@ -4184,7 +4184,7 @@
   }
 
   aic7xxx_run_waiting_queues(p);
-  spin_unlock_irqrestore(&p->host->host_lock, cpu_flags);
+  spin_unlock_irqrestore(p->host->host_lock, cpu_flags);
 }
 
 /*+F*************************************************************************
@@ -7011,7 +7011,7 @@
   p = (struct aic7xxx_host *)dev_id;
   if(!p)
     return;
-  spin_lock_irqsave(&p->host->host_lock, cpu_flags);
+  spin_lock_irqsave(p->host->host_lock, cpu_flags);
   p->flags |= AHC_IN_ISR;
   do
   {
@@ -7020,7 +7020,7 @@
   aic7xxx_done_cmds_complete(p);
   aic7xxx_run_waiting_queues(p);
   p->flags &= ~AHC_IN_ISR;
-  spin_unlock_irqrestore(&p->host->host_lock, cpu_flags);
+  spin_unlock_irqrestore(p->host->host_lock, cpu_flags);
 }
 
 /*+F*************************************************************************
@@ -11148,7 +11148,7 @@
   disable_irq(p->irq);
   aic7xxx_print_card(p);
   aic7xxx_print_scratch_ram(p);
-  spin_unlock_irq(&p->host->host_lock);
+  spin_unlock_irq(p->host->host_lock);
   for(;;) barrier();
 }
 
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/esp.c linux/drivers/scsi/esp.c
--- v2.5.2/linux/drivers/scsi/esp.c	Tue Dec 18 14:56:37 2001
+++ linux/drivers/scsi/esp.c	Tue Jan 15 10:52:11 2002
@@ -1,4 +1,4 @@
-/* $Id: esp.c,v 1.100 2001/12/11 04:55:48 davem Exp $
+/* $Id: esp.c,v 1.101 2002/01/15 06:48:55 davem Exp $
  * esp.c:  EnhancedScsiProcessor Sun SCSI driver code.
  *
  * Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu)
@@ -1918,7 +1918,7 @@
 	unsigned long flags;
 	int don;
 
-	spin_lock_irqsave(&esp->ehost->host_lock, flags);
+	spin_lock_irqsave(esp->ehost->host_lock, flags);
 
 	ESPLOG(("esp%d: Aborting command\n", esp->esp_id));
 	esp_dump_state(esp);
@@ -1934,7 +1934,7 @@
 		esp->msgout_len = 1;
 		esp->msgout_ctr = 0;
 		esp_cmd(esp, ESP_CMD_SATN);
-		spin_unlock_irqrestore(&esp->ehost->host_lock, flags);
+		spin_unlock_irqrestore(esp->ehost->host_lock, flags);
 		return SCSI_ABORT_PENDING;
 	}
 
@@ -1963,7 +1963,7 @@
 				if (don)
 					ESP_INTSON(esp->dregs);
 
-				spin_unlock_irqrestore(&esp->ehost->host_lock, flags);
+				spin_unlock_irqrestore(esp->ehost->host_lock, flags);
 				return SCSI_ABORT_SUCCESS;
 			}
 		}
@@ -1977,7 +1977,7 @@
 	if (esp->current_SC) {
 		if (don)
 			ESP_INTSON(esp->dregs);
-		spin_unlock_irqrestore(&esp->ehost->host_lock, flags);
+		spin_unlock_irqrestore(esp->ehost->host_lock, flags);
 		return SCSI_ABORT_BUSY;
 	}
 
@@ -1990,7 +1990,7 @@
 
 	if (don)
 		ESP_INTSON(esp->dregs);
-	spin_unlock_irqrestore(&esp->ehost->host_lock, flags);
+	spin_unlock_irqrestore(esp->ehost->host_lock, flags);
 	return SCSI_ABORT_SNOOZE;
 }
 
@@ -2052,9 +2052,9 @@
 	struct esp *esp = (struct esp *) SCptr->host->hostdata;
 	unsigned long flags;
 
-	spin_lock_irqsave(&esp->ehost->host_lock, flags);
+	spin_lock_irqsave(esp->ehost->host_lock, flags);
 	(void) esp_do_resetbus(esp);
-	spin_unlock_irqrestore(&esp->ehost->host_lock, flags);
+	spin_unlock_irqrestore(esp->ehost->host_lock, flags);
 
 	return SCSI_RESET_PENDING;
 }
@@ -4321,7 +4321,7 @@
 	struct esp *esp = dev_id;
 	unsigned long flags;
 
-	spin_lock_irqsave(&esp->ehost->host_lock, flags);
+	spin_lock_irqsave(esp->ehost->host_lock, flags);
 	if (ESP_IRQ_P(esp->dregs)) {
 		ESP_INTSOFF(esp->dregs);
 
@@ -4331,7 +4331,7 @@
 
 		ESP_INTSON(esp->dregs);
 	}
-	spin_unlock_irqrestore(&esp->ehost->host_lock, flags);
+	spin_unlock_irqrestore(esp->ehost->host_lock, flags);
 }
 
 int esp_revoke(Scsi_Device* SDptr)
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c
--- v2.5.2/linux/drivers/scsi/ide-scsi.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/ide-scsi.c	Tue Jan 15 11:27:47 2002
@@ -530,28 +530,33 @@
 	return 0;
 }
 
+int idescsi_reinit(ide_drive_t *drive);
+
 /*
  *	IDE subdriver functions, registered with ide.c
  */
 static ide_driver_t idescsi_driver = {
-	"ide-scsi",		/* name */
-	IDESCSI_VERSION,	/* version */
-	ide_scsi,		/* media */
-	0,			/* busy */
-	1,			/* supports_dma */
-	0,			/* supports_dsc_overlap */
-	idescsi_cleanup,	/* cleanup */
-	idescsi_do_request,	/* do_request */
-	idescsi_end_request,	/* end_request */
-	NULL,			/* ioctl */
-	idescsi_open,		/* open */
-	idescsi_ide_release,	/* release */
-	NULL,			/* media_change */
-	NULL,			/* revalidate */
-	NULL,			/* pre_reset */
-	NULL,			/* capacity */
-	NULL,			/* special */
-	NULL			/* proc */
+	name:			"ide-scsi",
+	version:		IDESCSI_VERSION,
+	media:			ide_scsi,
+	busy:			0,
+	supports_dma:		1,
+	supports_dsc_overlap:	0,
+	cleanup:		idescsi_cleanup,
+	standby:		NULL,
+	flushcache:		NULL,
+	do_request:		idescsi_do_request,
+	end_request:		idescsi_end_request,
+	ioctl:			NULL,
+	open:			idescsi_open,
+	release:		idescsi_ide_release,
+	media_change:		NULL,
+	revalidate:		NULL,
+	pre_reset:		NULL,
+	capacity:		NULL,
+	special:		NULL,
+	proc:			NULL,
+	driver_reinit:		idescsi_reinit,
 };
 
 int idescsi_init (void);
@@ -562,6 +567,43 @@
 	NULL
 };
 
+int idescsi_reinit (ide_drive_t *drive)
+{
+#if 0
+	idescsi_scsi_t *scsi;
+	byte media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255};
+	int i, failed, id;
+
+	if (!idescsi_initialized)
+		return 0;
+	for (i = 0; i < MAX_HWIFS * MAX_DRIVES; i++)
+		idescsi_drives[i] = NULL;
+
+	MOD_INC_USE_COUNT;
+	for (i = 0; media[i] != 255; i++) {
+		failed = 0;
+		while ((drive = ide_scan_devices (media[i], idescsi_driver.name, NULL, failed++)) != NULL) {
+
+			if ((scsi = (idescsi_scsi_t *) kmalloc (sizeof (idescsi_scsi_t), GFP_KERNEL)) == NULL) {
+				printk (KERN_ERR "ide-scsi: %s: Can't allocate a scsi structure\n", drive->name);
+				continue;
+			}
+			if (ide_register_subdriver (drive, &idescsi_driver, IDE_SUBDRIVER_VERSION)) {
+				printk (KERN_ERR "ide-scsi: %s: Failed to register the driver with ide.c\n", drive->name);
+				kfree (scsi);
+				continue;
+			}
+			for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++);
+				idescsi_setup (drive, scsi, id);
+			failed--;
+		}
+	}
+	ide_register_module(&idescsi_module);
+	MOD_DEC_USE_COUNT;
+#endif
+	return 0;
+}
+
 /*
  *	idescsi_init will register the driver for each scsi.
  */
@@ -592,7 +634,7 @@
 				continue;
 			}
 			for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++);
-			idescsi_setup (drive, scsi, id);
+				idescsi_setup (drive, scsi, id);
 			failed--;
 		}
 	}
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/qlogicfc.c linux/drivers/scsi/qlogicfc.c
--- v2.5.2/linux/drivers/scsi/qlogicfc.c	Tue Dec 18 14:56:37 2001
+++ linux/drivers/scsi/qlogicfc.c	Tue Jan 15 10:52:11 2002
@@ -1375,7 +1375,7 @@
 	hostdata->explore_timer.data = 0;
 	del_timer(&hostdata->explore_timer);
 
-	spin_lock_irqsave(&host->host_lock, flags);
+	spin_lock_irqsave(host->host_lock, flags);
 
 	if (hostdata->adapter_state & AS_REDO_FABRIC_PORTDB || hostdata->adapter_state & AS_REDO_LOOP_PORTDB) {
 		isp2x00_make_portdb(host);
@@ -1422,7 +1422,7 @@
 		hostdata->adapter_state = AS_LOOP_GOOD;
 	}
 
-	spin_unlock_irqrestore(&host->host_lock, flags);
+	spin_unlock_irqrestore(host->host_lock, flags);
 
 }
 
@@ -1433,9 +1433,9 @@
 	struct Scsi_Host *host = dev_id;
 	unsigned long flags;
 
-	spin_lock_irqsave(&host->host_lock, flags);
+	spin_lock_irqsave(host->host_lock, flags);
 	isp2x00_intr_handler(irq, dev_id, regs);
-	spin_unlock_irqrestore(&host->host_lock, flags);
+	spin_unlock_irqrestore(host->host_lock, flags);
 }
 
 void isp2x00_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/qlogicisp.c linux/drivers/scsi/qlogicisp.c
--- v2.5.2/linux/drivers/scsi/qlogicisp.c	Tue Dec 18 14:56:37 2001
+++ linux/drivers/scsi/qlogicisp.c	Tue Jan 15 10:52:11 2002
@@ -973,9 +973,9 @@
 	struct Scsi_Host *host = dev_id;
 	unsigned long flags;
 
-	spin_lock_irqsave(&host->host_lock, flags);
+	spin_lock_irqsave(host->host_lock, flags);
 	isp1020_intr_handler(irq, dev_id, regs);
-	spin_unlock_irqrestore(&host->host_lock, flags);
+	spin_unlock_irqrestore(host->host_lock, flags);
 }
 
 void isp1020_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/qlogicpti.c linux/drivers/scsi/qlogicpti.c
--- v2.5.2/linux/drivers/scsi/qlogicpti.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/scsi/qlogicpti.c	Tue Jan 15 10:52:11 2002
@@ -1138,11 +1138,12 @@
 		int ok = host_byte(Cmnd->result) == DID_OK;
 		if (Cmnd->cmnd[0] == 0x12 && ok) {
 			unsigned char *iqd;
-			if (Cmnd->use_sg == 0) {
-				iqd = ((unsigned char *)Cmnd->buffer);
-			} else {
-				iqd = ((struct scatterlist *) Cmnd->request_buffer)->address;
-			}
+
+			if (Cmnd->use_sg != 0)
+				BUG();
+
+			iqd = ((unsigned char *)Cmnd->buffer);
+
 			/* tags handled in midlayer */
 			/* enable sync mode? */
 			if (iqd[7] & 0x10) {
@@ -1445,7 +1446,7 @@
 	spin_unlock(&qpti->lock);
 
 	if (dq != NULL) {
-		spin_lock(&qpti->qhost->host_lock);
+		spin_lock(qpti->qhost->host_lock);
 		do {
 			Scsi_Cmnd *next;
 
@@ -1453,7 +1454,7 @@
 			dq->scsi_done(dq);
 			dq = next;
 		} while (dq != NULL);
-		spin_unlock(&qpti->qhost->host_lock);
+		spin_unlock(qpti->qhost->host_lock);
 	}
 	__restore_flags(flags);
 }
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/scsi_debug.c linux/drivers/scsi/scsi_debug.c
--- v2.5.2/linux/drivers/scsi/scsi_debug.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/scsi/scsi_debug.c	Thu Jan 17 13:59:33 2002
@@ -3,8 +3,19 @@
  *
  *  Copyright (C) 1992  Eric Youngdale
  *  Simulate a host adapter with 2 disks attached.  Do a lot of checking
- *  to make sure that we are not getting blocks mixed up, and panic if
+ *  to make sure that we are not getting blocks mixed up, and PANIC if
  *  anything out of the ordinary is seen.
+ *
+ *  This version is more generic, simulating a variable number of disk 
+ *  (or disk like devices) sharing a common amount of RAM (default 8 MB
+ *  but can be set at driver/module load time).
+ *
+ *  For documentation see http://www.torque.net/sg/sdebug.html
+ *
+ *   D. Gilbert (dpg) work for MOD device test [20010421]
+ *   dpg, work for devfs large number of disks [20010809]
+ *   dpg, make more generic [20011123]
+ *   dpg, forked for lk 2.5 series [20011216, 20020101]
  */
 
 #include <linux/config.h>
@@ -18,7 +29,9 @@
 #include <linux/string.h>
 #include <linux/genhd.h>
 #include <linux/fs.h>
+#include <linux/init.h>
 #include <linux/proc_fs.h>
+#include <linux/smp_lock.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -27,201 +40,187 @@
 #include "scsi.h"
 #include "hosts.h"
 
-#include "sd.h"
-
 #include<linux/stat.h>
 
-/* A few options that we want selected */
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
+static char scsi_debug_version_str[] = "Version: 1.57 (20011216)";
 
-#define NR_HOSTS_PRESENT 1
-#define NR_FAKE_DISKS   3
-#define N_HEAD          255
-#define N_SECTOR        63
-#define N_CYLINDER      524
+#ifndef SCSI_CMD_READ_16
+#define SCSI_CMD_READ_16 0x88
+#endif
+#ifndef SCSI_CMD_WRITE_16
+#define SCSI_CMD_WRITE_16 0x8a
+#endif
+
+/* A few options that we want selected */
+#define DEF_NR_FAKE_DEVS   1
+#define DEF_DEV_SIZE_MB   8
+#define DEF_FAKE_BLK0   0
+
+static int scsi_debug_num_devs = DEF_NR_FAKE_DEVS;
+
+#define NR_HOSTS_PRESENT (((scsi_debug_num_devs - 1) / 7) + 1)
+#define N_HEAD          8
+#define N_SECTOR        32
 #define DISK_READONLY(TGT)      (0)
-#define DISK_REMOVEABLE(TGT)    (1)
-#define DEVICE_TYPE(TGT) (TGT == 2 ? TYPE_TAPE : TYPE_DISK);
+#define DISK_REMOVEABLE(TGT)    (0)
+#define DEVICE_TYPE(TGT) (TYPE_DISK);
+
+#define SCSI_DEBUG_MAILBOXES (scsi_debug_num_devs + 1)
+
+static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
+#define STORE_SIZE (scsi_debug_dev_size_mb * 1024 * 1024)
+#define STORE_ELEM_ORDER 1
+#define STORE_ELEM_SIZE (PAGE_SIZE * (1 << STORE_ELEM_ORDER))
+#define STORE_ELEMENTS ((STORE_SIZE / STORE_ELEM_SIZE) + 1)
+
+/* default sector size is 512 bytes, 2**9 bytes */
+#define POW2_SECT_SIZE 9
+#define SECT_SIZE (1 << POW2_SECT_SIZE)
+
+#define N_CYLINDER (STORE_SIZE / (SECT_SIZE * N_SECTOR * N_HEAD))
+
+static int scsi_debug_fake_blk0 = DEF_FAKE_BLK0;
 
 /* Do not attempt to use a timer to simulate a real disk with latency */
 /* Only use this in the actual kernel, not in the simulator. */
 #define IMMEDIATE
 
-/* Skip some consistency checking.  Good for benchmarking */
-#define SPEEDY
-/* Read return zeros. Undefine for benchmarking */
-#define CLEAR
-
-/* Number of real scsi disks that will be detected ahead of time */
-static int NR_REAL = -1;
-
-#define NR_BLK_DEV  12
-#ifndef MAJOR_NR
-#define MAJOR_NR 8
-#endif
+#define SDEBUG_SG_ADDRESS
+
 #define START_PARTITION 4
 
 /* Time to wait before completing a command */
 #define DISK_SPEED     (HZ/10)	/* 100ms */
 #define CAPACITY (N_HEAD * N_SECTOR * N_CYLINDER)
-#define SIZE(TGT) (TGT == 2 ? 2248 : 512)
+#define SECT_SIZE_PER(TGT) SECT_SIZE
+#define SECT_PER_ELEM (STORE_ELEM_SIZE / SECT_SIZE)
 
 static int starts[] =
 {N_SECTOR,
  N_HEAD * N_SECTOR,		/* Single cylinder */
  N_HEAD * N_SECTOR * 4,
- CAPACITY, 0};
+ 0 /* CAPACITY */, 0};
 static int npart = 0;
 
-#include "scsi_debug.h"
-#ifdef DEBUG
-#define DEB(x) x
-#else
-#define DEB(x)
-#endif
+typedef struct scsi_debug_store_elem {
+	unsigned char * p;
+} Sd_store_elem;
+
+static Sd_store_elem * store_arr = 0;
+
+typedef struct sdebug_dev_info {
+	Scsi_Device * sdp;
+	unsigned short host_no;
+	unsigned short id;
+	char reset;
+	char sb_index;
+} Sdebug_dev_info;
+static Sdebug_dev_info * devInfop;
+
+static int num_aborts = 0;
+static int num_dev_resets = 0;
+static int num_bus_resets = 0;
+static int num_host_resets = 0;
 
-#ifdef SPEEDY
-#define VERIFY1_DEBUG(RW)
-#define VERIFY_DEBUG(RW)
-#else
+static spinlock_t mailbox_lock = SPIN_LOCK_UNLOCKED;
+static rwlock_t sdebug_atomic_rw = RW_LOCK_UNLOCKED;
 
-#define VERIFY1_DEBUG(RW)                           \
-    if (bufflen != 1024) {printk("%d", bufflen); panic("(1)Bad bufflen");};         \
-    start = 0;                          \
-    if ((MINOR(SCpnt->request.rq_dev) & 0xf) != 0) start = starts[(MINOR(SCpnt->request.rq_dev) & 0xf) - 1];        \
-    if (bh){                            \
-	if (bh->b_size != 1024) panic ("Wrong bh size");    \
-	if ((bh->b_blocknr << 1) + start != block)          \
-	{   printk("Wrong bh block# %d %d ",bh->b_blocknr, block);  \
-	    panic ("Wrong bh block#"); \
-	};  \
-	if (bh->b_dev != SCpnt->request.rq_dev)  \
-	    panic ("Bad bh target"); \
-    };
-
-#define VERIFY_DEBUG(RW)                            \
-    if (bufflen != 1024 && (!SCpnt->use_sg)) {printk("%x %d\n ",bufflen, SCpnt->use_sg); panic("Bad bufflen");};    \
-    start = 0;                          \
-    if ((MINOR(SCpnt->request.rq_dev) & 0xf) > npart) panic ("Bad partition");    \
-    if ((MINOR(SCpnt->request.rq_dev) & 0xf) != 0) start = starts[(MINOR(SCpnt->request.rq_dev) & 0xf) - 1];        \
-    if (SCpnt->request.cmd != RW) panic ("Wrong  operation");       \
-    if (SCpnt->request.sector + start != block) panic("Wrong block.");  \
-    if (SCpnt->request.current_nr_sectors != 2 && (!SCpnt->use_sg)) panic ("Wrong # blocks");   \
-    if (SCpnt->request.bh){                         \
-	if (SCpnt->request.bh->b_size != 1024) panic ("Wrong bh size"); \
-	if ((SCpnt->request.bh->b_blocknr << 1) + start != block)           \
-	{   printk("Wrong bh block# %d %d ",SCpnt->request.bh->b_blocknr, block);  \
-	    panic ("Wrong bh block#"); \
-	};  \
-	if (SCpnt->request.bh->b_dev != SCpnt->request.rq_dev) \
-	    panic ("Bad bh target");\
-    };
-#endif
+#include "scsi_debug.h"
 
 typedef void (*done_fct_t) (Scsi_Cmnd *);
 
-static volatile done_fct_t do_done[SCSI_DEBUG_MAILBOXES] =
-{NULL,};
+static volatile done_fct_t * do_done = 0;
 
 struct Scsi_Host * SHpnt = NULL;
 
+static int scsi_debug_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
+			   int num, int * errstsp, Sdebug_dev_info * devip);
+static int scsi_debug_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
+			    int num, int * errstsp, Sdebug_dev_info * devip);
 static void scsi_debug_send_self_command(struct Scsi_Host * shpnt);
 static void scsi_debug_intr_handle(unsigned long);
+static Sdebug_dev_info * devInfoReg(Scsi_Device * sdp);
+static void mk_sense_buffer(Sdebug_dev_info * devip, int index, int key, 
+			    int asc, int asq, int inbandLen);
+static int check_reset(Scsi_Cmnd * SCpnt, Sdebug_dev_info * devip);
 
-static struct timer_list timeout[SCSI_DEBUG_MAILBOXES];
-
-Scsi_Cmnd *SCint[SCSI_DEBUG_MAILBOXES] =
-{NULL,};
-static char SCrst[SCSI_DEBUG_MAILBOXES] =
-{0,};
+static struct timer_list * timeout = 0;
+static Scsi_Cmnd ** SCint = 0;
 
 /*
  * Semaphore used to simulate bus lockups.
  */
 static int scsi_debug_lockup = 0;
 
-static char sense_buffer[128] =
-{0,};
+#define NUM_SENSE_BUFFS 4
+#define SENSE_BUFF_LEN 32
+static char sense_buffers[NUM_SENSE_BUFFS][SENSE_BUFF_LEN];
 
-static void scsi_dump(Scsi_Cmnd * SCpnt, int flag)
+static int made_block0 = 0;
+
+static void scsi_debug_mkblock0(unsigned char * buff, int bufflen,
+				Scsi_Cmnd * SCpnt)
 {
 	int i;
-#if 0
-	unsigned char *pnt;
-#endif
-	unsigned int *lpnt;
-	struct scatterlist *sgpnt = NULL;
-	printk("use_sg: %d", SCpnt->use_sg);
-	if (SCpnt->use_sg) {
-		sgpnt = (struct scatterlist *) SCpnt->buffer;
-		for (i = 0; i < SCpnt->use_sg; i++) {
-			printk(":%p %d\n", sgpnt[i].address, sgpnt[i].length);
-		};
-	} else {
-		printk("nosg: %p %p %d\n", SCpnt->request.buffer, SCpnt->buffer,
-		       SCpnt->bufflen);
-		lpnt = (int *) SCpnt->request.buffer;
-		if (lpnt)
-			printk(" (Alt %x) ", lpnt[15]);
-	};
-	lpnt = (unsigned int *) SCpnt;
-	for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) {
-		if ((i & 7) == 0)
-			printk("\n");
-		printk("%x ", *lpnt++);
-	};
-	printk("\n");
-	if (flag == 0)
-		return;
-#if 0
-	printk("\n");
-	lpnt = (unsigned int *) sgpnt[0].address;
-	for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) {
-		if ((i & 7) == 0)
-			printk("\n");
-		printk("%x ", *lpnt++);
-	};
-	printk("\n");
-#endif
+	struct partition *p;
+
+	memset(buff, 0, bufflen);
+	*((unsigned short *) (buff + 510)) = 0xAA55;
+	p = (struct partition *) (buff + 0x1be);
+	i = 0;
+	while (starts[i + 1]) {
+		int start_cyl, end_cyl;
+
+		start_cyl = starts[i] / N_HEAD / N_SECTOR;
+		end_cyl = (starts[i + 1] - 1) / N_HEAD / N_SECTOR;
+		p->boot_ind = 0;
+
+		p->head = (i == 0 ? 1 : 0);
+		p->sector = 1 | ((start_cyl >> 8) << 6);
+		p->cyl = (start_cyl & 0xff);
+
+		p->end_head = N_HEAD - 1;
+		p->end_sector = N_SECTOR | ((end_cyl >> 8) << 6);
+		p->end_cyl = (end_cyl & 0xff);
+
+		p->start_sect = starts[i];
+		p->nr_sects = starts[i + 1] - starts[i];
+		p->sys_ind = 0x83;	/* Linux ext2 partition */
+		p++;
+		i++;
+	}
+	if (!npart)
+		npart = i;
+	made_block0 = 1;
+	i = (bufflen > STORE_ELEM_SIZE) ? STORE_ELEM_SIZE : bufflen;
+	memcpy(store_arr[0].p, buff, i);
 }
 
 int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
 {
 	unchar *cmd = (unchar *) SCpnt->cmnd;
-	struct partition *p;
 	int block;
-	struct buffer_head *bh = NULL;
+	int upper_blk;
 	unsigned char *buff;
-	int nbytes, sgcount;
 	int scsi_debug_errsts;
-	struct scatterlist *sgpnt;
 	int target = SCpnt->target;
 	int bufflen = SCpnt->request_bufflen;
-	unsigned long flags;
-	int i;
-	sgcount = 0;
-	sgpnt = NULL;
-
-#ifdef CONFIG_SMP
-        /*
-         * The io_request_lock *must* be held at this point.
-         */
-        if( io_request_lock.lock == 0 )
-        {
-                printk("Warning - io_request_lock is not held in queuecommand\n");
-        }
-#endif
+	unsigned long iflags;
+	int i, num, capac;
+	Sdebug_dev_info * devip = NULL;
+	char * sbuff;
 
 	/*
-	 * If we are being notified of the mid-level reposessing a command due to timeout,
-	 * just return.
+	 * If we are being notified of the mid-level reposessing a command
+	 * due to timeout, just return.
 	 */
 	if (done == NULL) {
 		return 0;
 	}
-	DEB(if (target >= NR_FAKE_DISKS) {
-	    SCpnt->result = DID_TIME_OUT << 16; done(SCpnt); return 0;
-	    }
-	);
 
 	buff = (unsigned char *) SCpnt->request_buffer;
 
@@ -229,249 +228,201 @@
          * If a command comes for the ID of the host itself, just print
          * a silly message and return.
          */
-        if( target == 7 ) {
+        if(target == 7) {
                 printk("How do you do!\n");
                 SCpnt->result = 0;
                 done(SCpnt);
                 return 0;
         }
 
-	if (target >= NR_FAKE_DISKS || SCpnt->lun != 0) {
+	if ((target > 7) || (SCpnt->lun != 0)) {
 		SCpnt->result = DID_NO_CONNECT << 16;
 		done(SCpnt);
 		return 0;
 	}
-	if (SCrst[target] != 0 && !scsi_debug_lockup) {
-		SCrst[target] = 0;
-		memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
-		SCpnt->sense_buffer[0] = 0x70;
-		SCpnt->sense_buffer[2] = UNIT_ATTENTION;
-		SCpnt->result = (CHECK_CONDITION << 1);
-		done(SCpnt);
+#if 0
+	printk(KERN_INFO "sdebug:qc: host_no=%d, id=%d, sdp=%p, cmd=0x%x\n",
+	       (int)SCpnt->device->host->host_no, (int)SCpnt->device->id,
+	       SCpnt->device, (int)(unsigned char)*cmd);
+#endif
+	if (NULL == SCpnt->device->hostdata) {
+		devip = devInfoReg(SCpnt->device);
+		if (NULL == devip) {
+			SCpnt->result = DID_NO_CONNECT << 16;
+			done(SCpnt);
+			return 0;
+		}
+		SCpnt->device->hostdata = devip;
 	}
+	devip = SCpnt->device->hostdata;
+
 	switch (*cmd) {
-	case REQUEST_SENSE:
+	case REQUEST_SENSE:	/* mandatory */
 		SCSI_LOG_LLQUEUE(3, printk("Request sense...\n"));
-#ifndef DEBUG
-		{
-			int i;
-			printk("scsi_debug: Requesting sense buffer (%p %p %p %d):", SCpnt, buff, done, bufflen);
-			for (i = 0; i < 12; i++)
-				printk("%d ", sense_buffer[i]);
-			printk("\n");
-		};
-#endif
-		memset(buff, 0, bufflen);
-		memcpy(buff, sense_buffer, bufflen);
-		memset(sense_buffer, 0, sizeof(sense_buffer));
+		if (devip) {
+			sbuff = &sense_buffers[(int)devip->sb_index][0];
+			devip->sb_index = 0; 
+		}
+		else
+		    sbuff = &sense_buffers[0][0]; 
+		memcpy(buff, sbuff, (bufflen < SENSE_BUFF_LEN) ? 
+				     bufflen : SENSE_BUFF_LEN);
+		memset(sbuff, 0, SENSE_BUFF_LEN);
+		sbuff[0] = 0x70;
 		SCpnt->result = 0;
 		done(SCpnt);
 		return 0;
 	case START_STOP:
+		if (check_reset(SCpnt, devip)) {
+			done(SCpnt);
+			return 0;
+		}
 		SCSI_LOG_LLQUEUE(3, printk("START_STOP\n"));
 		scsi_debug_errsts = 0;
 		break;
 	case ALLOW_MEDIUM_REMOVAL:
+		if (check_reset(SCpnt, devip)) {
+			done(SCpnt);
+			return 0;
+		}
 		if (cmd[4]) {
-			SCSI_LOG_LLQUEUE(2, printk("Medium removal inhibited..."));
+			SCSI_LOG_LLQUEUE(2, printk(
+					"Medium removal inhibited..."));
 		} else {
-			SCSI_LOG_LLQUEUE(2, printk("Medium removal enabled..."));
+			SCSI_LOG_LLQUEUE(2, 
+					printk("Medium removal enabled..."));
 		}
 		scsi_debug_errsts = 0;
 		break;
-	case INQUIRY:
+	case INQUIRY:     /* mandatory */
 		SCSI_LOG_LLQUEUE(3, printk("Inquiry...(%p %d)\n", buff, bufflen));
 		memset(buff, 0, bufflen);
 		buff[0] = DEVICE_TYPE(target);
-		buff[1] = DISK_REMOVEABLE(target) ? 0x80 : 0;	/* Removable disk */
-		buff[2] = 1;
-		buff[4] = 33 - 5;
-		memcpy(&buff[8], "Foo Inc", 7);
-		memcpy(&buff[16], "XYZZY", 5);
-		memcpy(&buff[32], "1", 1);
+		buff[1] = DISK_REMOVEABLE(target) ? 0x80 : 0;	
+				/* Removable disk */
+		buff[2] = 2;	/* claim SCSI 2 */
+		buff[4] = 36 - 5;
+		memcpy(&buff[8], "Linux   ", 8);
+		memcpy(&buff[16], "scsi_debug      ", 16);
+		memcpy(&buff[32], "0002", 4);
+		scsi_debug_errsts = 0;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10)
+		if (SCpnt->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
+			SCpnt->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
+#endif
+		break;
+	case SEND_DIAGNOSTIC:     /* mandatory */
+		SCSI_LOG_LLQUEUE(3, printk("Send Diagnostic\n"));
+		if (buff)
+			memset(buff, 0, bufflen);
 		scsi_debug_errsts = 0;
 		break;
-	case TEST_UNIT_READY:
+	case TEST_UNIT_READY:     /* mandatory */
 		SCSI_LOG_LLQUEUE(3, printk("Test unit ready(%p %d)\n", buff, bufflen));
 		if (buff)
 			memset(buff, 0, bufflen);
 		scsi_debug_errsts = 0;
 		break;
 	case READ_CAPACITY:
+		if (check_reset(SCpnt, devip)) {
+			done(SCpnt);
+			return 0;
+		}
 		SCSI_LOG_LLQUEUE(3, printk("Read Capacity\n"));
                 SHpnt = SCpnt->host;
-		if (NR_REAL < 0)
-			NR_REAL = (MINOR(SCpnt->request.rq_dev) >> 4) & 0x0f;
 		memset(buff, 0, bufflen);
-		buff[0] = (CAPACITY >> 24);
-		buff[1] = (CAPACITY >> 16) & 0xff;
-		buff[2] = (CAPACITY >> 8) & 0xff;
-		buff[3] = CAPACITY & 0xff;
+		capac = CAPACITY - 1;
+		buff[0] = (capac >> 24);
+		buff[1] = (capac >> 16) & 0xff;
+		buff[2] = (capac >> 8) & 0xff;
+		buff[3] = capac & 0xff;
 		buff[4] = 0;
 		buff[5] = 0;
-		buff[6] = (SIZE(target) >> 8) & 0xff;	/* 512 byte sectors */
-		buff[7] = SIZE(target) & 0xff;
+		buff[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
+		buff[7] = SECT_SIZE_PER(target) & 0xff;
 
 		scsi_debug_errsts = 0;
 		break;
+	case SCSI_CMD_READ_16:	/* SBC-2 */
+	case READ_12:
 	case READ_10:
 	case READ_6:
-#ifdef DEBUG
-		printk("Read...");
-#endif
-		if ((*cmd) == READ_10)
-			block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
-		else
-			block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
-		VERIFY_DEBUG(READ);
-#if defined(SCSI_SETUP_LATENCY) || defined(SCSI_DATARATE)
-		{
-			int delay = SCSI_SETUP_LATENCY;
-
-			delay += SCpnt->request.nr_sectors * SCSI_DATARATE;
-			if (delay)
-				usleep(delay);
-		};
-#endif
-
-#ifdef DEBUG
-		printk("(r%d)", SCpnt->request.nr_sectors);
-#endif
-		nbytes = bufflen;
-		if (SCpnt->use_sg) {
-			sgcount = 0;
-			sgpnt = (struct scatterlist *) buff;
-			buff = sgpnt[sgcount].address;
-			bufflen = sgpnt[sgcount].length;
-			bh = SCpnt->request.bh;
-		};
-		scsi_debug_errsts = 0;
-		do {
-			VERIFY1_DEBUG(READ);
-			/* For the speedy test, we do not even want to fill the buffer with anything */
-#ifdef CLEAR
-			memset(buff, 0, bufflen);
-#endif
-			/* If this is block 0, then we want to read the partition table for this
-			 * device.  Let's make one up */
-			if (block == 0) {
-				int i;
-				memset(buff, 0, bufflen);
-				*((unsigned short *) (buff + 510)) = 0xAA55;
-				p = (struct partition *) (buff + 0x1be);
-				i = 0;
-				while (starts[i + 1]) {
-					int start_cyl, end_cyl;
-
-					start_cyl = starts[i] / N_HEAD / N_SECTOR;
-					end_cyl = (starts[i + 1] - 1) / N_HEAD / N_SECTOR;
-					p->boot_ind = 0;
-
-					p->head = (i == 0 ? 1 : 0);
-					p->sector = 1 | ((start_cyl >> 8) << 6);
-					p->cyl = (start_cyl & 0xff);
-
-					p->end_head = N_HEAD - 1;
-					p->end_sector = N_SECTOR | ((end_cyl >> 8) << 6);
-					p->end_cyl = (end_cyl & 0xff);
-
-					p->start_sect = starts[i];
-					p->nr_sects = starts[i + 1] - starts[i];
-					p->sys_ind = 0x81;	/* Linux partition */
-					p++;
-					i++;
-				};
-				if (!npart)
-					npart = i;
-				scsi_debug_errsts = 0;
-				break;
-			};
-#ifdef DEBUG
-			if (SCpnt->use_sg)
-				printk("Block %x (%d %d)\n", block, SCpnt->request.nr_sectors,
-				       SCpnt->request.current_nr_sectors);
-#endif
-
-#if 0
-			/* Simulate a disk change */
-			if (block == 0xfff0) {
-				sense_buffer[0] = 0x70;
-				sense_buffer[2] = UNIT_ATTENTION;
-				starts[0] += 10;
-				starts[1] += 10;
-				starts[2] += 10;
-
-#ifdef DEBUG
-				{
-					int i;
-					printk("scsi_debug: Filling sense buffer:");
-					for (i = 0; i < 12; i++)
-						printk("%d ", sense_buffer[i]);
-					printk("\n");
-				};
-#endif
-				scsi_debug_errsts = (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
-				break;
-			}	/* End phony disk change code */
-#endif
-
-#ifdef CLEAR
-			memcpy(buff, &target, sizeof(target));
-			memcpy(buff + sizeof(target), cmd, 24);
-			memcpy(buff + 60, &block, sizeof(block));
-			memcpy(buff + 64, SCpnt, sizeof(Scsi_Cmnd));
-#endif
-			nbytes -= bufflen;
-			if (SCpnt->use_sg) {
-#ifdef CLEAR
-				memcpy(buff + 128, bh, sizeof(struct buffer_head));
-#endif
-				block += bufflen >> 9;
-				bh = bh->b_reqnext;
-				sgcount++;
-				if (nbytes) {
-					if (!bh)
-						panic("Too few blocks for linked request.");
-					buff = sgpnt[sgcount].address;
-					bufflen = sgpnt[sgcount].length;
-				};
-			}
-		} while (nbytes);
-
+		if (check_reset(SCpnt, devip)) {
+			done(SCpnt);
+			return 0;
+		}
+		upper_blk = 0;
+		if ((*cmd) == SCSI_CMD_READ_16) {
+			upper_blk = cmd[5] + (cmd[4] << 8) + 
+				    (cmd[3] << 16) + (cmd[2] << 24);
+			block = cmd[9] + (cmd[8] << 8) + 
+				(cmd[7] << 16) + (cmd[6] << 24);
+			num = cmd[13] + (cmd[12] << 8) + 
+				(cmd[11] << 16) + (cmd[10] << 24);
+		}
+		else if ((*cmd) == READ_12) {
+			block = cmd[5] + (cmd[4] << 8) + 
+				(cmd[3] << 16) + (cmd[2] << 24);
+			num = cmd[9] + (cmd[8] << 8) + 
+				(cmd[7] << 16) + (cmd[6] << 24);
+		}
+		else if ((*cmd) == READ_10) {
+			block = cmd[5] + (cmd[4] << 8) + 
+				(cmd[3] << 16) + (cmd[2] << 24);
+			num = cmd[8] + (cmd[7] << 8);
+		}
+		else {
+			block = cmd[3] + (cmd[2] << 8) + 
+				((cmd[1] & 0x1f) << 16);
+			num = cmd[4];
+		}
+		if (scsi_debug_read(SCpnt, upper_blk, block, num, 
+				    &scsi_debug_errsts, devip))
+			break;
 		SCpnt->result = 0;
-		(done) (SCpnt);
+/* calls bottom half in upper layers before return from scsi_do_...() */
+		(done) (SCpnt);	
 		return 0;
-
-		if (SCpnt->use_sg && !scsi_debug_errsts)
-			if (bh)
-				scsi_dump(SCpnt, 0);
-		break;
+	case SCSI_CMD_WRITE_16:	/* SBC-2 */
+	case WRITE_12:
 	case WRITE_10:
 	case WRITE_6:
-#ifdef DEBUG
-		printk("Write\n");
-#endif
-		if ((*cmd) == WRITE_10)
-			block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
-		else
-			block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
-		VERIFY_DEBUG(WRITE);
-		/*      printk("(w%d)",SCpnt->request.nr_sectors); */
-		if (SCpnt->use_sg) {
-			if ((bufflen >> 9) != SCpnt->request.nr_sectors)
-				panic("Trying to write wrong number of blocks\n");
-			sgpnt = (struct scatterlist *) buff;
-			buff = sgpnt[sgcount].address;
-		};
-#if 0
-		if (block != *((unsigned long *) (buff + 60))) {
-			printk("%x %x :", block, *((unsigned long *) (buff + 60)));
-			scsi_dump(SCpnt, 1);
-			panic("Bad block written.\n");
-		};
-#endif
-		scsi_debug_errsts = 0;
-		break;
+		if (check_reset(SCpnt, devip)) {
+			done(SCpnt);
+			return 0;
+		}
+		upper_blk = 0;
+		if ((*cmd) == SCSI_CMD_WRITE_16) {
+			upper_blk = cmd[5] + (cmd[4] << 8) + 
+				    (cmd[3] << 16) + (cmd[2] << 24);
+			block = cmd[9] + (cmd[8] << 8) + 
+				(cmd[7] << 16) + (cmd[6] << 24);
+			num = cmd[13] + (cmd[12] << 8) + 
+				(cmd[11] << 16) + (cmd[10] << 24);
+		}
+		else if ((*cmd) == WRITE_12) {
+			block = cmd[5] + (cmd[4] << 8) + 
+				(cmd[3] << 16) + (cmd[2] << 24);
+			num = cmd[9] + (cmd[8] << 8) + 
+				(cmd[7] << 16) + (cmd[6] << 24);
+		}
+		else if ((*cmd) == WRITE_10) {
+			block = cmd[5] + (cmd[4] << 8) + 
+				(cmd[3] << 16) + (cmd[2] << 24);
+			num = cmd[8] + (cmd[7] << 8);
+		}
+		else {
+			block = cmd[3] + (cmd[2] << 8) + 
+				((cmd[1] & 0x1f) << 16);
+			num = cmd[4];
+		}
+		if (scsi_debug_write(SCpnt, upper_blk, block, num, 
+				     &scsi_debug_errsts, devip))
+			break;
+		SCpnt->result = 0;
+/* calls bottom half in upper layers before return from scsi_do_...() */
+		(done) (SCpnt);	
+		return 0;
 	case MODE_SENSE:
 		/*
 		 * Used to detect write protected status.
@@ -480,26 +431,36 @@
 		memset(buff, 0, 6);
 		break;
 	default:
+#if 0
 		SCSI_LOG_LLQUEUE(3, printk("Unknown command %d\n", *cmd));
 		SCpnt->result = DID_NO_CONNECT << 16;
 		done(SCpnt);
 		return 0;
-	};
+#else
+		if (check_reset(SCpnt, devip)) {
+			done(SCpnt);
+			return 0;
+		}
+		scsi_debug_errsts = (COMMAND_COMPLETE << 8) |
+				    (CHECK_CONDITION << 1);
+		mk_sense_buffer(devip, 2, ILLEGAL_REQUEST, 0x20, 0, 14);
+		break;
+#endif
+	}
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&mailbox_lock, iflags);
 	for (i = 0; i < SCSI_DEBUG_MAILBOXES; i++) {
 		if (timeout[i].function == NULL)
 			break;
-	};
+	}
 
 	/*
-	 * If all of the slots are full, just return 1.  The new error handling scheme
-	 * allows this, and the mid-level should queue things.
+	 * If all of the slots are full, just return 1.  The new error 
+	 * handling scheme allows this, and the mid-level should queue things.
 	 */
 	if (i >= SCSI_DEBUG_MAILBOXES || timeout[i].function != 0) {
 		SCSI_LOG_LLQUEUE(1, printk("Command rejected - host busy\n"));
-		restore_flags(flags);
+		spin_unlock_irqrestore(&mailbox_lock, iflags);
 		return 1;
 	}
 	SCSI_LOG_LLQUEUE(1, printk("Command accepted - slot %d\n", i));
@@ -511,7 +472,7 @@
 		do_done[i] = done;
 		scsi_debug_intr_handle(i);	/* No timer - do this one right away */
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&mailbox_lock, iflags);
 #else
 
 	SCpnt->result = scsi_debug_errsts;
@@ -521,19 +482,200 @@
 	SCint[i] = SCpnt;
 	do_done[i] = done;
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&mailbox_lock, iflags);
 	add_timer(&timeout[i]);
 	if (!done)
-		panic("scsi_debug_queuecommand: done can't be NULL\n");
+		printk("scsi_debug_queuecommand: done can't be NULL\n");
 
 #if 0
-	printk("Sending command (%d %x %d %d)...", i, done, timeout[i].expires, jiffies);
+	printk("Sending command (%d %x %d %d)...", i, done, 
+	       timeout[i].expires, jiffies);
 #endif
 #endif
 
 	return 0;
 }
 
+static int check_reset(Scsi_Cmnd * SCpnt, Sdebug_dev_info * devip)
+{
+	if (devip->reset) {
+		devip->reset = 0;
+		mk_sense_buffer(devip, 3, UNIT_ATTENTION, 0x29, 0, 14);
+		SCpnt->result = (COMMAND_COMPLETE << 8) | 
+				(CHECK_CONDITION << 1);
+                return 1;
+	}
+	return 0;
+}
+
+static inline 
+unsigned char * sdebug_scatg2virt(const struct scatterlist * sclp)
+{
+	if (NULL == sclp)
+		return NULL;
+	else if (sclp->page)
+		return (unsigned char *)page_address(sclp->page) + 
+		       sclp->offset;
+	else {
+#ifdef SDEBUG_SG_ADDRESS
+		return sclp->address;
+#else
+		return NULL;
+#endif
+	}
+}
+
+static int scsi_debug_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
+			   int num, int * errstsp, Sdebug_dev_info * devip)
+{
+        unsigned char *buff = (unsigned char *) SCpnt->request_buffer;
+        int nbytes, sgcount;
+        struct scatterlist *sgpnt = NULL;
+        int bufflen = SCpnt->request_bufflen;
+	unsigned long iflags;
+
+	if (upper_blk || (block + num > CAPACITY)) {
+		*errstsp = (COMMAND_COMPLETE << 8) |
+			   (CHECK_CONDITION << 1);
+		mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x21, 0, 14);
+		return 1;
+	}
+#if defined(SCSI_SETUP_LATENCY) || defined(SCSI_DATARATE)
+	{
+		int delay = SCSI_SETUP_LATENCY;
+
+		delay += SCpnt->request.nr_sectors * SCSI_DATARATE;
+		if (delay)
+			usleep(delay);
+	}
+#endif
+
+	read_lock_irqsave(&sdebug_atomic_rw, iflags);
+        sgcount = 0;
+	nbytes = bufflen;
+	/* printk("scsi_debug_read: block=%d, tot_bufflen=%d\n", 
+	       block, bufflen); */
+	if (SCpnt->use_sg) {
+		sgcount = 0;
+		sgpnt = (struct scatterlist *) buff;
+		buff = sdebug_scatg2virt(&sgpnt[sgcount]);
+		bufflen = sgpnt[sgcount].length;
+	}
+	*errstsp = 0;
+	do {
+		int resid, k, off, len, rem, blk;
+		unsigned char * bp;
+
+		/* If this is block 0, then we want to read the partition
+		 * table for this device.  Let's make one up */
+		if (scsi_debug_fake_blk0 && (block == 0) && (! made_block0)) {
+			scsi_debug_mkblock0(buff, bufflen, SCpnt);
+			*errstsp = 0;
+			break;
+		}
+		bp = buff;
+		blk = block;
+		for (resid = bufflen; resid > 0; resid -= len) {
+			k = blk / SECT_PER_ELEM; 
+			off = (blk % SECT_PER_ELEM) * SECT_SIZE;
+			rem = STORE_ELEM_SIZE - off;
+			len = (resid > rem) ? rem : resid;
+/* printk("sdr: blk=%d k=%d off=%d rem=%d resid"
+			       "=%d len=%d  sgcount=%d\n", blk, k, 
+				off, rem, resid, len, sgcount); */
+			memcpy(bp, store_arr[k].p + off, len);
+			bp += len;
+			blk += len / SECT_SIZE;
+		}
+#if 0
+		/* Simulate a disk change */
+		if (block == 0xfff0) {
+			sense_buffer[0] = 0x70;
+			sense_buffer[2] = UNIT_ATTENTION;
+			starts[0] += 10;
+			starts[1] += 10;
+			starts[2] += 10;
+
+			*errstsp = (COMMAND_COMPLETE << 8) | 
+				   (CHECK_CONDITION << 1);
+			read_unlock_irqrestore(&sdebug_atomic_rw, iflags);
+			return 1;
+		}	/* End phony disk change code */
+#endif
+		nbytes -= bufflen;
+		if (SCpnt->use_sg) {
+			block += bufflen >> POW2_SECT_SIZE;
+			sgcount++;
+			if (nbytes) {
+				buff = sdebug_scatg2virt(&sgpnt[sgcount]);
+				bufflen = sgpnt[sgcount].length;
+			}
+		}
+		else if (nbytes > 0)
+			printk("sdebug_read: unexpected nbytes=%d\n", nbytes);
+	} while (nbytes);
+	read_unlock_irqrestore(&sdebug_atomic_rw, iflags);
+	return 0;
+}
+
+static int scsi_debug_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
+			    int num, int * errstsp, Sdebug_dev_info * devip)
+{
+        unsigned char *buff = (unsigned char *) SCpnt->request_buffer;
+        int nbytes, sgcount;
+        struct scatterlist *sgpnt = NULL;
+        int bufflen = SCpnt->request_bufflen;
+	unsigned long iflags;
+
+	if (upper_blk || (block + num > CAPACITY)) {
+		*errstsp = (COMMAND_COMPLETE << 8) |
+			   (CHECK_CONDITION << 1);
+		mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x21, 0, 14);
+		return 1;
+	}
+
+	write_lock_irqsave(&sdebug_atomic_rw, iflags);
+        sgcount = 0;
+	nbytes = bufflen;
+	if (SCpnt->use_sg) {
+		sgcount = 0;
+		sgpnt = (struct scatterlist *) buff;
+		buff = sdebug_scatg2virt(&sgpnt[sgcount]);
+		bufflen = sgpnt[sgcount].length;
+	}
+	*errstsp = 0;
+	do {
+		int resid, k, off, len, rem, blk;
+		unsigned char * bp;
+
+		bp = buff;
+		blk = block;
+		for (resid = bufflen; resid > 0; resid -= len) {
+			k = blk / SECT_PER_ELEM; 
+			off = (blk % SECT_PER_ELEM) * SECT_SIZE;
+			rem = STORE_ELEM_SIZE - off;
+			len = (resid > rem) ? rem : resid;
+			memcpy(store_arr[k].p + off, bp, len);
+			bp += len;
+			blk += len / SECT_SIZE;
+		}
+
+		nbytes -= bufflen;
+		if (SCpnt->use_sg) {
+			block += bufflen >> POW2_SECT_SIZE;
+			sgcount++;
+			if (nbytes) {
+				buff = sdebug_scatg2virt(&sgpnt[sgcount]);
+				bufflen = sgpnt[sgcount].length;
+			}
+		}
+		else if (nbytes > 0)
+			printk("sdebug_write: unexpected nbytes=%d\n", nbytes);
+	} while (nbytes);
+	write_unlock_irqrestore(&sdebug_atomic_rw, iflags);
+	return 0;
+}
+
 static void scsi_debug_send_self_command(struct Scsi_Host * shpnt)
 {
 	static unsigned char cmd[6] =
@@ -581,10 +723,6 @@
 {
 	Scsi_Cmnd *SCtmp;
 	void (*my_done) (Scsi_Cmnd *);
-#ifdef DEBUG
-	int to;
-#endif
-
 #if 0
 	del_timer(&timeout[indx]);
 #endif
@@ -599,59 +737,219 @@
 		printk("scsi_debug_intr_handle: Unexpected interrupt\n");
 		return;
 	}
-#ifdef DEBUG
+#if 0
 	printk("In intr_handle...");
 	printk("...done %d %x %d %d\n", i, my_done, to, jiffies);
 	printk("In intr_handle: %d %x %x\n", i, SCtmp, my_done);
 #endif
 
 	my_done(SCtmp);
-#ifdef DEBUG
+#if 0
 	printk("Called done.\n");
 #endif
 }
 
+static int initialized = 0;
+
+static int do_init(void)
+{
+	int sz;
+
+	starts[3] = CAPACITY;
+	sz = sizeof(Sd_store_elem) * STORE_ELEMENTS;
+	store_arr = kmalloc(sz, GFP_ATOMIC);
+	if (NULL == store_arr)
+		return 1;
+	memset(store_arr, 0, sz);
+
+	sz = sizeof(done_fct_t) * SCSI_DEBUG_MAILBOXES;
+	do_done = kmalloc(sz, GFP_ATOMIC);
+	if (NULL == do_done)
+		goto out;
+	memset((void *)do_done, 0, sz);
+
+	sz = sizeof(struct timer_list) * SCSI_DEBUG_MAILBOXES;
+	timeout = kmalloc(sz, GFP_ATOMIC);
+	if (NULL == timeout)
+		goto out;
+	memset(timeout, 0, sz);
+
+	sz = sizeof(Scsi_Cmnd *) * SCSI_DEBUG_MAILBOXES;
+	SCint = kmalloc(sz, GFP_ATOMIC);
+	if (NULL == SCint)
+		goto out;
+	memset(SCint, 0, sz);
+
+	return 0;
+
+out:
+	if (store_arr)
+		kfree(store_arr);
+	if (do_done)
+		kfree((void *)do_done);
+	if (timeout)
+		kfree(timeout);
+	if (SCint)
+		kfree(SCint);
+	return 1;
+}
+
+static void do_end(void)
+{
+	kfree(SCint);
+	kfree(timeout);
+	kfree((void *)do_done);
+	kfree(store_arr);
+}
+
 
 int scsi_debug_detect(Scsi_Host_Template * tpnt)
 {
-	int i;
+	int k, num, sz;
+
+	if (0 == initialized) {
+		++initialized;
+		sz = sizeof(Sdebug_dev_info) * scsi_debug_num_devs;
+		devInfop = kmalloc(sz, GFP_ATOMIC);
+		if (NULL == devInfop) {
+			printk("scsi_debug_detect: out of memory, 0.5\n");
+			return 0;
+		}
+		memset(devInfop, 0, sz);
+		if (do_init()) {
+			printk("scsi_debug_detect: out of memory, 0\n");
+			return 0;
+		}
+		for (k = 0; k < STORE_ELEMENTS; ++k) {
+			store_arr[k].p = (unsigned char *)
+				__get_free_pages(GFP_ATOMIC, STORE_ELEM_ORDER);
+			if (0 == store_arr[k].p)
+				goto detect_err;
+			memset(store_arr[k].p, 0, STORE_ELEM_SIZE);
+		}
+		for (k = 0; k < NUM_SENSE_BUFFS; ++k)
+			sense_buffers[k][0] = 0x70;
+		for (k = 0; k < NR_HOSTS_PRESENT; k++) {
+			tpnt->proc_name = "scsi_debug";	/* In the loop??? */
+			scsi_register(tpnt, 0);
+		}
+		return NR_HOSTS_PRESENT;
+	}
+	else {
+		printk("scsi_debug_detect: called again\n");
+		return 0;
+	}
 
-	for (i = 0; i < NR_HOSTS_PRESENT; i++) {
-		tpnt->proc_name = "scsi_debug";	/* Huh? In the loop??? */
-		scsi_register(tpnt, 0);
+detect_err:
+	num = k;
+	for (k = 0; k < STORE_ELEMENTS; ++k) {
+		if (0 != store_arr[k].p) {
+			free_pages((unsigned long)store_arr[k].p, 
+				   STORE_ELEM_ORDER);
+			store_arr[k].p = NULL;
+		}
 	}
-	return NR_HOSTS_PRESENT;
+	printk("scsi_debug_detect: out of memory: %d out of %d bytes\n",
+	       (int)(num * STORE_ELEM_SIZE), 
+	       (int)(scsi_debug_dev_size_mb * 1024 * 1024));
+	return 0;
+}
+
+
+static int num_releases = 0;
+
+int scsi_debug_release(struct Scsi_Host * hpnt)
+{
+	int k;
+	
+	scsi_unregister(hpnt);
+	if (++num_releases != NR_HOSTS_PRESENT)
+		return 0;
+
+	for (k = 0; k < STORE_ELEMENTS; ++k) {
+		if (0 != store_arr[k].p) {
+			free_pages((unsigned long)store_arr[k].p, 
+				   STORE_ELEM_ORDER);
+			store_arr[k].p = NULL;
+		}
+	}
+	do_end();
+	kfree(devInfop);
+	return 0;
+}
+
+static Sdebug_dev_info * devInfoReg(Scsi_Device * sdp)
+{
+	int k;
+	unsigned short host_no, id;
+	Sdebug_dev_info * devip;
+
+	host_no = sdp->host->host_no;
+	id = (unsigned short)sdp->id;
+	for (k = 0; k < scsi_debug_num_devs; ++k) {
+		devip = &devInfop[k];
+		if (devip->sdp && (host_no == devip->host_no) &&
+		    (id == devip->id)) {
+			devip->sdp = sdp; /* overwrite previous sdp */
+			return devip;
+		}
+		if (NULL == devip->sdp) {
+			devip->sdp = sdp;
+			devip->host_no = host_no;
+			devip->id = id;
+			devip->reset = 1;
+			devip->sb_index = 0;
+			return devip;
+		}
+	}
+	return NULL;
+}
+
+static void mk_sense_buffer(Sdebug_dev_info * devip, int index, int key, 
+			    int asc, int asq, int inbandLen)
+{
+	char * sbuff;
+	if ((index < 0) || (index >= NUM_SENSE_BUFFS))
+		return;
+	if (devip)
+		devip->sb_index = index;
+	sbuff = &sense_buffers[index][0];
+	memset(sbuff, 0, SENSE_BUFF_LEN);
+	sbuff[0] = 0x70;
+	sbuff[2] = key;
+	sbuff[7] = (inbandLen > 7) ? (inbandLen - 8) : 0;
+	sbuff[12] = asc;
+	sbuff[13] = asq;
 }
 
 int scsi_debug_abort(Scsi_Cmnd * SCpnt)
 {
-#if 0
+#if 1
+	++num_aborts;
+	return SUCCESS;
+#else
 	int j;
 	void (*my_done) (Scsi_Cmnd *);
-	unsigned long flags;
-#endif
-
-	DEB(printk("scsi_debug_abort\n"));
-#if 0
+	unsigned long iflags;
 	SCpnt->result = SCpnt->abort_reason << 16;
 	for (j = 0; j < SCSI_DEBUG_MAILBOXES; j++) {
 		if (SCpnt == SCint[j]) {
 			my_done = do_done[j];
 			my_done(SCpnt);
-			save_flags(flags);
-			cli();
+			spin_lock_irqsave(&mailbox_lock, iflags);
 			timeout[j] = 0;
 			SCint[j] = NULL;
 			do_done[j] = NULL;
-			restore_flags(flags);
-		};
-	};
-#endif
+			spin_unlock_irqrestore(&mailbox_lock, iflags);
+		}
+	}
 	return SCSI_ABORT_SNOOZE;
+#endif
 }
 
 int scsi_debug_biosparam(Disk * disk, kdev_t dev, int *info)
 {
+	/* int size = disk->capacity; */
 	info[0] = N_HEAD;
 	info[1] = N_SECTOR;
 	info[2] = N_CYLINDER;
@@ -660,35 +958,130 @@
 	return 0;
 }
 
+#if 0
 int scsi_debug_reset(Scsi_Cmnd * SCpnt, unsigned int why)
 {
 	int i;
-	unsigned long flags;
+	unsigned long iflags;
 
 	void (*my_done) (Scsi_Cmnd *);
 	printk("Bus unlocked by reset - %d\n", why);
 	scsi_debug_lockup = 0;
-	DEB(printk("scsi_debug_reset called\n"));
 	for (i = 0; i < SCSI_DEBUG_MAILBOXES; i++) {
 		if (SCint[i] == NULL)
 			continue;
 		SCint[i]->result = DID_RESET << 16;
 		my_done = do_done[i];
 		my_done(SCint[i]);
-		save_flags(flags);
-		cli();
+		spin_lock_irqsave(&mailbox_lock, iflags);
 		SCint[i] = NULL;
 		do_done[i] = NULL;
 		timeout[i].function = NULL;
-		restore_flags(flags);
+		spin_unlock_irqrestore(&mailbox_lock, iflags);
 	}
 	return SCSI_RESET_SUCCESS;
 }
+#endif
+
+int scsi_debug_device_reset(Scsi_Cmnd * SCpnt)
+{
+	Scsi_Device * sdp;
+	int k;
+
+	++num_dev_resets;
+	if (SCpnt && ((sdp = SCpnt->device))) {
+		for (k = 0; k < scsi_debug_num_devs; ++k) {
+			if (sdp->hostdata == (devInfop + k))
+				break;
+		}
+		if (k < scsi_debug_num_devs)
+			devInfop[k].reset = 1;
+	}
+	return SUCCESS;
+}
 
-const char *scsi_debug_info(void)
+int scsi_debug_bus_reset(Scsi_Cmnd * SCpnt)
 {
-	static char buffer[] = " ";	/* looks nicer without anything here */
-	return buffer;
+	Scsi_Device * sdp;
+	struct Scsi_Host * hp;
+	int k;
+
+	++num_bus_resets;
+	if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
+		for (k = 0; k < scsi_debug_num_devs; ++k) {
+			if (hp == devInfop[k].sdp->host)
+				devInfop[k].reset = 1;
+		}
+	}
+	return SUCCESS;
+}
+
+int scsi_debug_host_reset(Scsi_Cmnd * SCpnt)
+{
+	int k;
+
+	++num_host_resets;
+	for (k = 0; k < scsi_debug_num_devs; ++k)
+		devInfop[k].reset = 1;
+
+	return SUCCESS;
+}
+
+#ifndef MODULE
+static int __init scsi_debug_num_devs_setup(char *str)
+{   
+    int tmp; 
+    
+    if (get_option(&str, &tmp) == 1) {
+        if (tmp > 0)
+            scsi_debug_num_devs = tmp;
+        return 1;
+    } else {
+        printk("scsi_debug_num_devs: usage scsi_debug_num_devs=<n> "
+               "(<n> can be from 1 to around 2000)\n");
+        return 0;
+    }
+}
+
+__setup("scsi_debug_num_devs=", scsi_debug_num_devs_setup);
+
+static int __init scsi_debug_dev_size_mb_setup(char *str)
+{   
+    int tmp; 
+    
+    if (get_option(&str, &tmp) == 1) {
+        if (tmp > 0)
+            scsi_debug_dev_size_mb = tmp;
+        return 1;
+    } else {
+        printk("scsi_debug_dev_size_mb: usage scsi_debug_dev_size_mb=<n>\n"
+               "    (<n> is number of MB ram shared by all devs\n");
+        return 0;
+    }
+}
+
+__setup("scsi_debug_dev_size_mb=", scsi_debug_dev_size_mb_setup);
+#endif
+
+MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
+MODULE_DESCRIPTION("SCSI debug adapter driver");
+MODULE_PARM(scsi_debug_num_devs, "i");
+MODULE_PARM_DESC(scsi_debug_num_devs, "number of SCSI devices to simulate");
+MODULE_PARM(scsi_debug_dev_size_mb, "i");
+MODULE_PARM_DESC(scsi_debug_dev_size_mb, "size in MB of ram shared by devs");
+
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+static char sdebug_info[256];
+
+const char * scsi_debug_info(struct Scsi_Host * shp)
+{
+	sprintf(sdebug_info, "scsi_debug, %s, num_devs=%d, "
+		"dev_size_mb=%d\n", scsi_debug_version_str,
+		scsi_debug_num_devs, scsi_debug_dev_size_mb);
+	return sdebug_info;
 }
 
 /* scsi_debug_proc_info
@@ -738,10 +1131,20 @@
 
 	}
 	begin = 0;
-	pos = len = sprintf(buffer,
-	"This driver is not a real scsi driver, but it plays one on TV.\n"
+	pos = len = sprintf(buffer, "scsi_debug adapter driver, %s\n"
+	    "num_devs=%d, shared (ram) size=%d MB, sector_size=%d bytes\n" 
+	    "cylinders=%d, heads=%d, sectors=%d\n"
+	    "number of aborts=%d, device_reset=%d, bus_resets=%d, " 
+	    "host_resets=%d\n",
+	    scsi_debug_version_str, scsi_debug_num_devs, 
+	    scsi_debug_dev_size_mb, SECT_SIZE,
+	    N_CYLINDER, N_HEAD, N_SECTOR,
+	    num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
+#if 0
+	 "This driver is not a real scsi driver, but it plays one on TV.\n"
 	 "It is very handy for debugging specific problems because you\n"
 			 "can simulate a variety of error conditions\n");
+#endif
 	if (pos < offset) {
 		len = 0;
 		begin = pos;
@@ -754,44 +1157,8 @@
 	return (len);
 }
 
-#ifdef CONFIG_USER_DEBUG
-/*
- * This is a hack for the user space emulator.  It allows us to
- * "insert" arbitrary numbers of additional drivers.
- */
-void *scsi_debug_get_handle(void)
-{
-	static Scsi_Host_Template driver_copy = SCSI_DEBUG;
-	void *rtn;
-	rtn = kmalloc(sizeof(driver_copy), GFP_ATOMIC);
-	if(rtn==NULL)
-		return NULL;
-	memcpy(rtn, (void *) &driver_copy, sizeof(driver_copy));
-	return rtn;
-}
-#endif
-
 /* Eventually this will go into an include file, but this will be later */
-static Scsi_Host_Template driver_template = SCSI_DEBUG;
+static Scsi_Host_Template driver_template = SCSI_DEBUG_TEMPLATE;
 
 #include "scsi_module.c"
 
-/*
- * Overrides for Emacs so that we almost follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
-MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/scsi_debug.h linux/drivers/scsi/scsi_debug.h
--- v2.5.2/linux/drivers/scsi/scsi_debug.h	Tue Dec 18 14:56:38 2001
+++ linux/drivers/scsi/scsi_debug.h	Thu Jan 17 13:59:33 2002
@@ -8,34 +8,41 @@
 int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
 int scsi_debug_abort(Scsi_Cmnd *);
 int scsi_debug_biosparam(Disk *, kdev_t, int[]);
-int scsi_debug_reset(Scsi_Cmnd *, unsigned int);
+int scsi_debug_bus_reset(Scsi_Cmnd *);
+int scsi_debug_dev_reset(Scsi_Cmnd *);
+int scsi_debug_host_reset(Scsi_Cmnd *);
 int scsi_debug_proc_info(char *, char **, off_t, int, int, int);
+const char * scsi_debug_info(struct Scsi_Host *);
 
 #ifndef NULL
 #define NULL 0
 #endif
 
-
-#define SCSI_DEBUG_MAILBOXES 1
-
 /*
- * Allow the driver to reject commands.  Thus we accept only one, but
- * and the mid-level will queue the remainder.
+ * This driver is written for the lk 2.5 series
  */
 #define SCSI_DEBUG_CANQUEUE  255
 
-#define SCSI_DEBUG {proc_info:         scsi_debug_proc_info,	\
+#define SCSI_DEBUG_MAX_CMD_LEN 16
+
+#define SCSI_DEBUG_TEMPLATE \
+		   {proc_info:         scsi_debug_proc_info,	\
 		    name:              "SCSI DEBUG",		\
+		    info:              scsi_debug_info,		\
 		    detect:            scsi_debug_detect,	\
+		    release:           scsi_debug_release,	\
 		    queuecommand:      scsi_debug_queuecommand, \
-		    abort:             scsi_debug_abort,	\
-		    reset:             scsi_debug_reset,	\
+		    eh_abort_handler:  scsi_debug_abort,	\
+		    eh_bus_reset_handler: scsi_debug_bus_reset,	\
+		    eh_device_reset_handler: scsi_debug_device_reset,	\
+		    eh_host_reset_handler: scsi_debug_host_reset,	\
 		    bios_param:        scsi_debug_biosparam,	\
 		    can_queue:         SCSI_DEBUG_CANQUEUE,	\
 		    this_id:           7,			\
-		    sg_tablesize:      16,			\
+		    sg_tablesize:      64,			\
 		    cmd_per_lun:       3,			\
 		    unchecked_isa_dma: 0,			\
 		    use_clustering:    ENABLE_CLUSTERING,	\
 }
+
 #endif
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c
--- v2.5.2/linux/drivers/scsi/sg.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/sg.c	Thu Jan 17 13:59:33 2002
@@ -19,9 +19,9 @@
  */
 #include <linux/config.h>
 #ifdef CONFIG_PROC_FS
- static char sg_version_str[] = "Version: 3.1.20 (20010814)";
+ static char sg_version_str[] = "Version: 3.5.23 (20020103)";
 #endif
- static int sg_version_num = 30120; /* 2 digits for each component */
+ static int sg_version_num = 30523; /* 2 digits for each component */
 /*
  *  D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
  *      - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
@@ -76,12 +76,18 @@
 #include <linux/version.h>
 #endif /* LINUX_VERSION_CODE */
 
+#define SG_STILL_HAVE_ADDRESS_IN_SCATTERLIST
+
 #define SG_ALLOW_DIO_DEF 0
 #define SG_ALLOW_DIO_CODE	/* compile out be commenting this define */
 #ifdef SG_ALLOW_DIO_CODE
 #include <linux/iobuf.h>
 #endif
 
+#define SG_NEW_KIOVEC 0	/* use alloc_kiovec(), not alloc_kiovec_sz() */
+
+#define SG_MAX_DEVS_MASK ((1U << KDEV_MINOR_BITS) - 1)
+
 int sg_big_buff = SG_DEF_RESERVED_SIZE;
 /* N.B. This variable is readable and writeable via
    /proc/scsi/sg/def_reserved_size . Each time sg_open() is called a buffer
@@ -95,14 +101,8 @@
 #define SG_SECTOR_SZ 512
 #define SG_SECTOR_MSK (SG_SECTOR_SZ - 1)
 
-#define SG_LOW_POOL_THRESHHOLD 30
-#define SG_MAX_POOL_SECTORS 320  /* Max. number of pool sectors to take */
-
-static int sg_pool_secs_avail = SG_MAX_POOL_SECTORS;
-
 #define SG_HEAP_PAGE 1  /* heap from kernel via get_free_pages() */
 #define SG_HEAP_KMAL 2  /* heap from kernel via kmalloc() */
-#define SG_HEAP_POOL 3  /* heap from scsi dma pool (mid-level) */
 #define SG_USER_MEM 4   /* memory belongs to user space */
 
 #define SG_DEV_ARR_LUMP 6 /* amount to over allocate sg_dev_arr by */
@@ -136,10 +136,10 @@
 typedef struct sg_scatter_hold  /* holding area for scsi scatter gather info */
 {
     unsigned short k_use_sg;    /* Count of kernel scatter-gather pieces */
-    unsigned short sglist_len;  /* size of malloc'd scatter-gather list */
+    unsigned short sglist_len;  /* size of malloc'd scatter-gather list ++ */
     unsigned bufflen;           /* Size of (aggregate) data buffer */
     unsigned b_malloc_len;      /* actual len malloc'ed in buffer */
-    void * buffer;              /* Data buffer or scatter list,12 bytes each*/
+    void * buffer;              /* Data buffer or scatter list + mem_src_arr */
     struct kiobuf * kiobp;      /* for direct IO information */
     char mapped;                /* indicates kiobp has locked pages */
     char buffer_mem_src;        /* heap whereabouts of 'buffer' */
@@ -182,6 +182,7 @@
     char cmd_q;         /* 1 -> allow command queuing, 0 -> don't */
     char next_cmd_len;  /* 0 -> automatic (def), >0 -> use on next write() */
     char keep_orphan;   /* 0 -> drop orphan (def), 1 -> keep for read() */
+    char mmap_called;   /* 0 -> mmap() never called on this fd */
 } Sg_fd; /* 2760 bytes long on i386 */
 
 typedef struct sg_device /* holds the state of each scsi generic device */
@@ -203,7 +204,8 @@
 static int sg_start_req(Sg_request * srp);
 static void sg_finish_rem_req(Sg_request * srp);
 static int sg_build_indi(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size);
-static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp);
+static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp,
+			 int tablesize);
 static ssize_t sg_new_read(Sg_fd * sfp, char * buf, size_t count,
 			   Sg_request * srp);
 static ssize_t sg_new_write(Sg_fd * sfp, const char * buf, size_t count,
@@ -233,13 +235,15 @@
 static Sg_request * sg_add_request(Sg_fd * sfp);
 static int sg_remove_request(Sg_fd * sfp, Sg_request * srp);
 static int sg_res_in_use(Sg_fd * sfp);
-static void sg_clr_srpnt(Scsi_Request * SRpnt);
 static int sg_ms_to_jif(unsigned int msecs);
-static unsigned sg_jif_to_ms(int jifs);
+static inline unsigned sg_jif_to_ms(int jifs);
 static int sg_allow_access(unsigned char opcode, char dev_type);
 static int sg_build_dir(Sg_request * srp, Sg_fd * sfp, int dxfer_len);
 static void sg_unmap_and(Sg_scatter_hold * schp, int free_also);
 static Sg_device * sg_get_dev(int dev);
+static inline int sg_alloc_kiovec(int nr, struct kiobuf **bufp, int *szp);
+static inline void sg_free_kiovec(int nr, struct kiobuf **bufp, int *szp);
+static inline unsigned char * sg_scatg2virt(const struct scatterlist * sclp);
 #ifdef CONFIG_PROC_FS
 static int sg_last_dev(void);
 #endif
@@ -337,9 +341,8 @@
     Sg_device * sdp;
     Sg_fd * sfp;
 
-    if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) {
+    if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp)))
         return -ENXIO;
-    }
     SCSI_LOG_TIMEOUT(3, printk("sg_release: dev=%d\n", minor(sdp->i_rdev)));
     sg_fasync(-1, filp, 0);   /* remove filp from async notification list */
     if (0 == sg_remove_sfp(sdp, sfp)) { /* Returns 1 when sdp gone */
@@ -615,6 +618,20 @@
 	sg_remove_request(sfp, srp);
 	return -ENOSYS;
     }
+    if (hp->flags & SG_FLAG_MMAP_IO) {
+    	if (hp->dxfer_len > sfp->reserve.bufflen) {
+	    sg_remove_request(sfp, srp);
+	    return -ENOMEM;	/* MMAP_IO size must fit in reserve buffer */
+	}
+	if (hp->flags & SG_FLAG_DIRECT_IO) {
+	    sg_remove_request(sfp, srp);
+	    return -EINVAL;	/* either MMAP_IO or DIRECT_IO (not both) */
+	}
+	if (sg_res_in_use(sfp)) {
+	    sg_remove_request(sfp, srp);
+	    return -EBUSY;	/* reserve buffer already being used */
+	}
+    }
     timeout = sg_ms_to_jif(srp->header.timeout);
     if ((! hp->cmdp) || (hp->cmd_len < 6) || (hp->cmd_len > sizeof(cmnd))) {
 	sg_remove_request(sfp, srp);
@@ -681,7 +698,6 @@
     srp->my_cmdp = SRpnt;
     q = &SRpnt->sr_device->request_queue;
     SRpnt->sr_request.rq_dev = sdp->i_rdev;
-    SRpnt->sr_request.rq_status = RQ_ACTIVE;
     SRpnt->sr_sense_buffer[0] = 0;
     SRpnt->sr_cmd_len = hp->cmd_len;
     if (! (hp->flags & SG_FLAG_LUN_INHIBIT)) {
@@ -849,7 +865,7 @@
         result = get_user(val, (int *)arg);
         if (result) return result;
         if (val != sfp->reserve.bufflen) {
-            if (sg_res_in_use(sfp))
+            if (sg_res_in_use(sfp) || sfp->mmap_called)
                 return -EBUSY;
             sg_remove_scat(&sfp->reserve);
             sg_build_reserve(sfp, val);
@@ -1030,6 +1046,146 @@
     return (retval < 0) ? retval : 0;
 }
 
+static inline unsigned char * sg_scatg2virt(const struct scatterlist * sclp)
+{
+    return (sclp && sclp->page) ? 
+    		(unsigned char *)page_address(sclp->page) + sclp->offset :
+		NULL;
+}
+
+static void sg_rb_correct4mmap(Sg_scatter_hold * rsv_schp, int startFinish)
+{
+    void * page_ptr;
+    struct page * page;
+    int k, m;
+
+    SCSI_LOG_TIMEOUT(3, printk("sg_rb_correct4mmap: startFinish=%d, "
+			   "scatg=%d\n", startFinish, rsv_schp->k_use_sg)); 
+    /* N.B. correction _not_ applied to base page of aech allocation */
+    if (rsv_schp->k_use_sg) { /* reserve buffer is a scatter gather list */
+        struct scatterlist * sclp = rsv_schp->buffer;
+
+        for (k = 0; k < rsv_schp->k_use_sg; ++k, ++sclp) {
+	    for (m = PAGE_SIZE; m < sclp->length; m += PAGE_SIZE) {
+		page_ptr = sg_scatg2virt(sclp) + m;
+		page = virt_to_page(page_ptr);
+		if (startFinish)
+		    get_page(page);	/* increment page count */
+		else {
+		    if (page_count(page) > 0)
+			put_page_testzero(page); /* decrement page count */
+		}
+	    }
+        }
+    }
+    else { /* reserve buffer is just a single allocation */
+	for (m = PAGE_SIZE; m < rsv_schp->bufflen; m += PAGE_SIZE) {
+	    page_ptr = (unsigned char *)rsv_schp->buffer + m;
+	    page = virt_to_page(page_ptr);
+	    if (startFinish)
+		get_page(page);	/* increment page count */
+	    else {
+		if (page_count(page) > 0)
+		    put_page_testzero(page); /* decrement page count */
+	    }
+	}
+    }
+}
+
+static struct page * sg_vma_nopage(struct vm_area_struct *vma, 
+				   unsigned long addr, int unused)
+{
+    Sg_fd * sfp;
+    struct page * page = NOPAGE_SIGBUS;
+    void * page_ptr = NULL;
+    unsigned long offset;
+    Sg_scatter_hold * rsv_schp;
+
+    if ((NULL == vma) || (! (sfp = (Sg_fd *)vma->vm_private_data)))
+	return page;
+    rsv_schp = &sfp->reserve;
+    offset = addr - vma->vm_start;
+    if (offset >= rsv_schp->bufflen)
+	return page;
+    SCSI_LOG_TIMEOUT(3, printk("sg_vma_nopage: offset=%lu, scatg=%d\n", 
+			       offset, rsv_schp->k_use_sg));
+    if (rsv_schp->k_use_sg) { /* reserve buffer is a scatter gather list */
+        int k;
+        unsigned long sa = vma->vm_start;
+        unsigned long len;
+        struct scatterlist * sclp = rsv_schp->buffer;
+
+        for (k = 0; (k < rsv_schp->k_use_sg) && (sa < vma->vm_end);
+             ++k, ++sclp) {
+            len = vma->vm_end - sa;
+            len = (len < sclp->length) ? len : sclp->length;
+	    if (offset < len) {
+		page_ptr = sg_scatg2virt(sclp) + offset;
+		page = virt_to_page(page_ptr);
+		get_page(page);	/* increment page count */
+		break;
+	    }
+            sa += len;
+	    offset -= len;
+        }
+    }
+    else { /* reserve buffer is just a single allocation */
+        page_ptr = (unsigned char *)rsv_schp->buffer + offset;
+	page = virt_to_page(page_ptr);
+	get_page(page);	/* increment page count */
+    }
+    return page;
+}
+
+static struct vm_operations_struct sg_mmap_vm_ops = {
+    nopage : sg_vma_nopage,
+};
+
+static int sg_mmap(struct file * filp, struct vm_area_struct *vma)
+{
+    Sg_fd * sfp;
+    unsigned long req_sz = vma->vm_end - vma->vm_start;
+    Sg_scatter_hold * rsv_schp;
+
+    if ((! filp) || (! vma) || (! (sfp = (Sg_fd *)filp->private_data)))
+        return -ENXIO;
+    SCSI_LOG_TIMEOUT(3, printk("sg_mmap starting, vm_start=%p, len=%d\n", 
+			       (void *)vma->vm_start, (int)req_sz));
+    if (vma->vm_pgoff)
+    	return -EINVAL;		/* want no offset */
+    rsv_schp = &sfp->reserve;
+    if (req_sz > rsv_schp->bufflen)
+    	return -ENOMEM;		/* cannot map more than reserved buffer */
+
+    if (rsv_schp->k_use_sg) { /* reserve buffer is a scatter gather list */
+    	int k;
+	unsigned long sa = vma->vm_start;
+	unsigned long len;
+	struct scatterlist * sclp = rsv_schp->buffer;
+
+	for (k = 0; (k < rsv_schp->k_use_sg) && (sa < vma->vm_end); 
+	     ++k, ++sclp) {
+	    if (0 != sclp->offset)
+	    	return -EFAULT;     /* non page aligned memory ?? */
+	    len = vma->vm_end - sa;
+	    len = (len < sclp->length) ? len : sclp->length;
+	    sa += len;
+	}
+    }
+    else { /* reserve buffer is just a single allocation */
+    	if ((unsigned long)rsv_schp->buffer & (PAGE_SIZE - 1))
+	    return -EFAULT;	/* non page aligned memory ?? */
+    }
+    if (0 == sfp->mmap_called) {
+    	sg_rb_correct4mmap(rsv_schp, 1);  /* do only once per fd lifetime */
+	sfp->mmap_called = 1;
+    }
+    vma->vm_flags |= (VM_RESERVED | VM_IO);
+    vma->vm_private_data = sfp;
+    vma->vm_ops = &sg_mmap_vm_ops;
+    return 0;
+}
+
 /* This function is a "bottom half" handler that is called by the
  * mid level when a command is completed (or has failed). */
 static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt)
@@ -1076,7 +1232,14 @@
     srp->data.sglist_len = SRpnt->sr_sglist_len;
     srp->data.bufflen = SRpnt->sr_bufflen;
     srp->data.buffer = SRpnt->sr_buffer;
-    sg_clr_srpnt(SRpnt);
+    /* now clear out request structure */
+    SRpnt->sr_use_sg = 0;
+    SRpnt->sr_sglist_len = 0;
+    SRpnt->sr_bufflen = 0;
+    SRpnt->sr_buffer = NULL;
+    SRpnt->sr_underflow = 0;
+    SRpnt->sr_request.rq_dev = mk_kdev(0, 0);  /* "sg" _disowns_ request blk */
+
     srp->my_cmdp = NULL;
     srp->done = 1;
     read_unlock(&sg_dev_arr_lock);
@@ -1121,14 +1284,15 @@
 	if (NULL == sfp->headrp) {
             SCSI_LOG_TIMEOUT(1,
 		printk("sg...bh: already closed, final cleanup\n"));
-            sg_remove_sfp(sdp, sfp);
+            if (0 == sg_remove_sfp(sdp, sfp)) { /* device still present */
+		sdp->device->access_count--;
+		if (sdp->device->host->hostt->module)
+		    __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module);
+	    }
+	    if (sg_template.module)
+		    __MOD_DEC_USE_COUNT(sg_template.module);
 	    sfp = NULL;
         }
-	sdp->device->access_count--;
-	if (sg_template.module)
-		__MOD_DEC_USE_COUNT(sg_template.module);
-	if (sdp->device->host->hostt->module)
-	    __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module);
     }
     else if (srp && srp->orphan) {
 	if (sfp->keep_orphan)
@@ -1152,6 +1316,7 @@
 	poll:		sg_poll,
 	ioctl:		sg_ioctl,
 	open:		sg_open,
+	mmap:		sg_mmap,
 	release:	sg_release,
 	fasync:		sg_fasync,
 };
@@ -1176,7 +1341,7 @@
     if(!sg_registered) {
 	if (devfs_register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops))
         {
-            printk("Unable to get major %d for generic SCSI device\n",
+            printk(KERN_ERR "Unable to get major %d for generic SCSI device\n",
                    SCSI_GENERIC_MAJOR);
 	    write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
             return 1;
@@ -1189,7 +1354,7 @@
     sg_dev_arr = (Sg_device **)kmalloc(sg_template.dev_max * 
     					sizeof(Sg_device *), GFP_ATOMIC);
     if (NULL == sg_dev_arr) {
-        printk("sg_init: no space for sg_dev_arr\n");
+        printk(KERN_ERR "sg_init: no space for sg_dev_arr\n");
 	write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
         return 1;
     }
@@ -1212,8 +1377,8 @@
 	    sg_big_buff = tmp;
 	return 1;
     } else {
-	printk("sg_def_reserved_size : usage sg_def_reserved_size=n "
-	       "(n could be 65536, 131072 or 262144)\n");
+	printk(KERN_WARNING "sg_def_reserved_size : usage "
+	    "sg_def_reserved_size=n (n could be 65536, 131072 or 262144)\n");
 	return 0;
     }
 }
@@ -1238,7 +1403,7 @@
 	if (NULL == tmp_da) {
 	    scsidp->attached--;
 	    write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-	    printk("sg_attach: device array cannot be resized\n");
+	    printk(KERN_ERR "sg_attach: device array cannot be resized\n");
 	    return 1;
 	}
 	memset(tmp_da, 0, tmp_dev_max * sizeof(Sg_device *));
@@ -1250,13 +1415,13 @@
 
     for(k = 0; k < sg_template.dev_max; k++)
         if(! sg_dev_arr[k]) break;
-    if (k > MINORMASK) {
+    if (k > SG_MAX_DEVS_MASK) {
 	scsidp->attached--;
 	write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-	printk("Unable to attach sg device <%d, %d, %d, %d>"
+	printk(KERN_WARNING "Unable to attach sg device <%d, %d, %d, %d>"
 	       " type=%d, minor number exceed %d\n", scsidp->host->host_no, 
 	       scsidp->channel, scsidp->id, scsidp->lun, scsidp->type,
-	       MINORMASK);
+	       SG_MAX_DEVS_MASK);
 	return 1;
     }
     if(k < sg_template.dev_max)
@@ -1266,7 +1431,7 @@
     if (NULL == sdp) {
 	scsidp->attached--;
 	write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-	printk("sg_attach: Sg_device cannot be allocated\n");
+	printk(KERN_ERR "sg_attach: Sg_device cannot be allocated\n");
 	return 1;
     }
 
@@ -1293,8 +1458,8 @@
 	case TYPE_WORM:
 	case TYPE_TAPE: break;
 	default:
-	    printk("Attached scsi generic sg%d at scsi%d, channel %d, id %d,"
-		   " lun %d,  type %d\n", k, scsidp->host->host_no, 
+	    printk(KERN_NOTICE "Attached scsi generic sg%d at scsi%d, channel"
+	    	   " %d, id %d, lun %d,  type %d\n", k, scsidp->host->host_no, 
 		   scsidp->channel, scsidp->id, scsidp->lun, scsidp->type);
     }
     return 0;
@@ -1371,7 +1536,10 @@
 
 MODULE_AUTHOR("Douglas Gilbert");
 MODULE_DESCRIPTION("SCSI generic (sg) driver");
+
+#ifdef MODULE_LICENSE
 MODULE_LICENSE("GPL");
+#endif
 
 MODULE_PARM(def_reserved_size, "i");
 MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd");
@@ -1417,9 +1585,8 @@
 	if (res <= 0)   /* -ve -> error, 0 -> done, 1 -> try indirect */
 	    return res;
     }
-    if ((! sg_res_in_use(sfp)) && (dxfer_len <= rsv_schp->bufflen)) {
+    if ((! sg_res_in_use(sfp)) && (dxfer_len <= rsv_schp->bufflen))
 	sg_link_reserve(sfp, srp, dxfer_len);
-    }
     else {
 	res = sg_build_indi(req_schp, sfp, dxfer_len);
         if (res) {
@@ -1445,23 +1612,24 @@
     sg_remove_request(sfp, srp);
 }
 
-static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp)
+static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp,
+			 int tablesize)
 {
     int mem_src, ret_sz;
-    int sg_bufflen = PAGE_SIZE;
     int elem_sz = sizeof(struct scatterlist) + sizeof(char);
-    int mx_sc_elems = (sg_bufflen / elem_sz) - 1;
+    /* scatter gather array, followed by mem_src_arr (array of chars) */
+    int sg_bufflen = tablesize * elem_sz;
+    int mx_sc_elems = tablesize;
 
     mem_src = SG_HEAP_KMAL;
-    schp->buffer = (struct scatterlist *)sg_malloc(sfp, sg_bufflen,
-						   &ret_sz, &mem_src);
-    schp->buffer_mem_src = (char)mem_src;
+    schp->buffer = sg_malloc(sfp, sg_bufflen, &ret_sz, &mem_src);
     if (! schp->buffer)
 	return -ENOMEM;
     else if (ret_sz != sg_bufflen) {
 	sg_bufflen = ret_sz;
-	mx_sc_elems = (sg_bufflen / elem_sz) - 1;
+	mx_sc_elems = sg_bufflen / elem_sz;
     }
+    schp->buffer_mem_src = (char)mem_src;
     schp->sglist_len = sg_bufflen;
     memset(schp->buffer, 0, sg_bufflen);
     return mx_sc_elems; /* number of scat_gath elements allocated */
@@ -1470,13 +1638,15 @@
 static void sg_unmap_and(Sg_scatter_hold * schp, int free_also)
 {
 #ifdef SG_ALLOW_DIO_CODE
+    int nbhs = 0;
+
     if (schp && schp->kiobp) {
 	if (schp->mapped) {
 	    unmap_kiobuf(schp->kiobp);
 	    schp->mapped = 0;
 	}
 	if (free_also) {
-	    free_kiovec(1, &schp->kiobp);
+	    sg_free_kiovec(1, &schp->kiobp, &nbhs);
 	    schp->kiobp = NULL;
 	}
     }
@@ -1494,10 +1664,12 @@
     sg_io_hdr_t * hp = &srp->header;
     Sg_scatter_hold * schp = &srp->data;
     int sg_tablesize = sfp->parentdp->sg_tablesize;
+    int nbhs = 0;
 
-    res = alloc_kiovec(1, &schp->kiobp);
+    res = sg_alloc_kiovec(1, &schp->kiobp, &nbhs);
     if (0 != res) {
-	SCSI_LOG_TIMEOUT(5, printk("sg_build_dir: alloc_kiovec res=%d\n", res));
+	SCSI_LOG_TIMEOUT(5, printk("sg_build_dir: sg_alloc_kiovec res=%d\n", 
+			 res));
 	return 1;
     }
     res = map_user_kiobuf((SG_DXFER_TO_DEV == hp->dxfer_direction) ? 1 : 0,
@@ -1527,7 +1699,7 @@
 	hp->info |= SG_INFO_DIRECT_IO;
 	return 0;
     }
-    mx_sc_elems = sg_build_sgat(schp, sfp);
+    mx_sc_elems = sg_build_sgat(schp, sfp, sg_tablesize);
     if (mx_sc_elems <= 1) {
 	sg_unmap_and(schp, 1);
 	sg_remove_scat(schp);
@@ -1535,19 +1707,22 @@
     }
     mem_src_arr = schp->buffer + (mx_sc_elems * sizeof(struct scatterlist));
     for (k = 0, sclp = schp->buffer, rem_sz = dxfer_len;
-	 (k < sg_tablesize) && (rem_sz > 0) && (k < mx_sc_elems);
+	 (rem_sz > 0) && (k < mx_sc_elems);
 	 ++k, ++sclp) {
 	offset = (0 == k) ? kp->offset : 0;
 	num = (rem_sz > (PAGE_SIZE - offset)) ? (PAGE_SIZE - offset) :
 						rem_sz;
+	sclp->page = kp->maplist[k];
+	sclp->offset = offset;
+#ifdef SG_STILL_HAVE_ADDRESS_IN_SCATTERLIST
 	sclp->address = page_address(kp->maplist[k]) + offset;
-	sclp->page = NULL;
+#endif
 	sclp->length = num;
 	mem_src_arr[k] = SG_USER_MEM;
 	rem_sz -= num;
 	SCSI_LOG_TIMEOUT(5,
 	    printk("sg_build_dir: k=%d, a=0x%p, len=%d, ms=%d\n",
-	    k, sclp->address, num, mem_src_arr[k]));
+	    k, sg_scatg2virt(sclp), num, mem_src_arr[k]));
     }
     schp->k_use_sg = k;
     SCSI_LOG_TIMEOUT(5,
@@ -1569,7 +1744,7 @@
 {
     int ret_sz, mem_src;
     int blk_size = buff_size;
-    char * p = NULL;
+    unsigned char * p = NULL;
 
     if ((blk_size < 0) || (! sfp))
         return -EFAULT;
@@ -1609,14 +1784,14 @@
 	char * mem_src_arr;
 
         /* N.B. ret_sz and mem_src carried into this block ... */
-	mx_sc_elems = sg_build_sgat(schp, sfp);
+	mx_sc_elems = sg_build_sgat(schp, sfp, sg_tablesize);
 	if (mx_sc_elems < 0)
 	    return mx_sc_elems; /* most likely -ENOMEM */
 	mem_src_arr = schp->buffer +
 		      (mx_sc_elems * sizeof(struct scatterlist));
 
 	for (k = 0, sclp = schp->buffer, rem_sz = blk_size;
-	     (k < sg_tablesize) && (rem_sz > 0) && (k < mx_sc_elems);
+	     (rem_sz > 0) && (k < mx_sc_elems);
              ++k, rem_sz -= ret_sz, ++sclp) {
 	    if (first)
                 first = 0;
@@ -1627,14 +1802,17 @@
                 if (! p)
                     break;
             }
+            sclp->page = virt_to_page(p);
+            sclp->offset = (unsigned long)p & ~PAGE_MASK;
+#ifdef SG_STILL_HAVE_ADDRESS_IN_SCATTERLIST
             sclp->address = p;
-	    sclp->page = NULL;
+#endif
             sclp->length = ret_sz;
 	    mem_src_arr[k] = mem_src;
 
 	    SCSI_LOG_TIMEOUT(5,
 		printk("sg_build_build: k=%d, a=0x%p, len=%d, ms=%d\n",
-                k, sclp->address, ret_sz, mem_src));
+                k, sg_scatg2virt(sclp), ret_sz, mem_src));
         } /* end of for loop */
 	schp->k_use_sg = k;
 	SCSI_LOG_TIMEOUT(5,
@@ -1664,7 +1842,8 @@
 	if (schp->bufflen < num_xfer)
 	    num_xfer = schp->bufflen;
     }
-    if ((num_xfer <= 0) || (new_interface && (SG_FLAG_NO_DXFER & hp->flags)))
+    if ((num_xfer <= 0) || 
+    	(new_interface && ((SG_FLAG_NO_DXFER | SG_FLAG_MMAP_IO) & hp->flags)))
 	return 0;
 
     SCSI_LOG_TIMEOUT(4,
@@ -1698,14 +1877,15 @@
 	struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
 	char * mem_src_arr = sg_get_sgat_msa(schp);
 	ksglen = (int)sclp->length;
-	p = sclp->address;
+	p = sg_scatg2virt(sclp);
 
 	for (j = 0, k = 0; j < onum; ++j) {
 	    res = sg_u_iovec(hp, iovec_count, j, 1, &usglen, &up);
 	    if (res) return res;
 
 	    for (; (k < schp->k_use_sg) && p;
-		 ++k, ++sclp, ksglen = (int)sclp->length, p = sclp->address) {
+		 ++k, ++sclp, ksglen = (int)sclp->length, 
+		 	p = sg_scatg2virt(sclp)) {
 		ok = (SG_USER_MEM != mem_src_arr[k]);
 		if (usglen <= 0)
 		    break;
@@ -1766,7 +1946,7 @@
 static char * sg_get_sgat_msa(Sg_scatter_hold * schp)
 {
     int elem_sz = sizeof(struct scatterlist) + sizeof(char);
-    int mx_sc_elems = (schp->sglist_len / elem_sz) - 1;
+    int mx_sc_elems = schp->sglist_len / elem_sz;
     return schp->buffer + (sizeof(struct scatterlist) * mx_sc_elems);
 }
 
@@ -1779,14 +1959,17 @@
         struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
 	char * mem_src_arr = sg_get_sgat_msa(schp);
 
-	for (k = 0; (k < schp->k_use_sg) && sclp->address; ++k, ++sclp) {
+	for (k = 0; (k < schp->k_use_sg) && sg_scatg2virt(sclp); ++k, ++sclp) {
 	    mem_src = mem_src_arr[k];
 	    SCSI_LOG_TIMEOUT(5,
 		printk("sg_remove_scat: k=%d, a=0x%p, len=%d, ms=%d\n",
-                       k, sclp->address, sclp->length, mem_src));
-            sg_free(sclp->address, sclp->length, mem_src);
-            sclp->address = NULL;
+                       k, sg_scatg2virt(sclp), sclp->length, mem_src));
+            sg_free(sg_scatg2virt(sclp), sclp->length, mem_src);
 	    sclp->page = NULL;
+            sclp->offset = 0;
+#ifdef SG_STILL_HAVE_ADDRESS_IN_SCATTERLIST
+	    sclp->address = 0;
+#endif
             sclp->length = 0;
         }
 	sg_free(schp->buffer, schp->sglist_len, schp->buffer_mem_src);
@@ -1814,7 +1997,8 @@
 	if (schp->bufflen < num_xfer)
 	    num_xfer = schp->bufflen;
     }
-    if ((num_xfer <= 0) || (new_interface && (SG_FLAG_NO_DXFER & hp->flags)))
+    if ((num_xfer <= 0) || 
+    	(new_interface && ((SG_FLAG_NO_DXFER | SG_FLAG_MMAP_IO) & hp->flags)))
 	return 0;
 
     SCSI_LOG_TIMEOUT(4,
@@ -1848,14 +2032,15 @@
 	struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
 	char * mem_src_arr = sg_get_sgat_msa(schp);
 	ksglen = (int)sclp->length;
-	p = sclp->address;
+	p = sg_scatg2virt(sclp);
 
 	for (j = 0, k = 0; j < onum; ++j) {
 	    res = sg_u_iovec(hp, iovec_count, j, 0, &usglen, &up);
 	    if (res) return res;
 
 	    for (; (k < schp->k_use_sg) && p;
-		 ++k, ++sclp, ksglen = (int)sclp->length, p = sclp->address) {
+		 ++k, ++sclp, ksglen = (int)sclp->length, 
+		 	p = sg_scatg2virt(sclp)) {
 		ok = (SG_USER_MEM != mem_src_arr[k]);
 		if (usglen <= 0)
 		    break;
@@ -1896,14 +2081,14 @@
         int k, num;
         struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
 
-	for (k = 0; (k < schp->k_use_sg) && sclp->address; ++k, ++sclp) {
+	for (k = 0; (k < schp->k_use_sg) && sg_scatg2virt(sclp); ++k, ++sclp) {
             num = (int)sclp->length;
             if (num > num_read_xfer) {
-                __copy_to_user(outp, sclp->address, num_read_xfer);
+                __copy_to_user(outp, sg_scatg2virt(sclp), num_read_xfer);
                 break;
             }
             else {
-                __copy_to_user(outp, sclp->address, num);
+                __copy_to_user(outp, sg_scatg2virt(sclp), num);
                 num_read_xfer -= num;
                 if (num_read_xfer <= 0)
                     break;
@@ -1949,7 +2134,7 @@
             if (rem <= num) {
 		if (0 == k) {
 		    req_schp->k_use_sg = 0;
-		    req_schp->buffer = sclp->address;
+		    req_schp->buffer = sg_scatg2virt(sclp);
 		}
 		else {
     		    sfp->save_scat_len = num;
@@ -2189,6 +2374,8 @@
     if (sfp->reserve.bufflen > 0) {
     SCSI_LOG_TIMEOUT(6, printk("__sg_remove_sfp:    bufflen=%d, k_use_sg=%d\n",
 	     (int)sfp->reserve.bufflen, (int)sfp->reserve.k_use_sg));
+	if (sfp->mmap_called)
+	    sg_rb_correct4mmap(&sfp->reserve, 0); /* undo correction */
 	sg_remove_scat(&sfp->reserve);
     }
     sfp->parentdp = NULL;
@@ -2237,7 +2424,7 @@
 	/* MOD_INC's to inhibit unloading sg and associated adapter driver */
 	if (sg_template.module)
 	    __MOD_INC_USE_COUNT(sg_template.module);
-	 if (sdp->device->host->hostt->module)
+	if (sdp->device->host->hostt->module)
 	    __MOD_INC_USE_COUNT(sdp->device->host->hostt->module);
         SCSI_LOG_TIMEOUT(1, printk(
           "sg_remove_sfp: worrisome, %d writes pending\n", dirty));
@@ -2270,30 +2457,6 @@
         if (resp && retSzp) *retSzp = rqSz;
         return resp;
     }
-    if (SG_HEAP_POOL == mem_src) {
-        int num_sect = rqSz / SG_SECTOR_SZ;
-
-        if (0 != (rqSz & SG_SECTOR_MSK)) {
-            if (! retSzp)
-                return resp;
-            ++num_sect;
-            rqSz = num_sect * SG_SECTOR_SZ;
-        }
-        while (num_sect > 0) {
-            if ((num_sect <= sg_pool_secs_avail)) {
-                resp = kmalloc(rqSz, page_mask);
-                if (resp) {
-                    if (retSzp) *retSzp = rqSz;
-                    sg_pool_secs_avail -= num_sect;
-                    return resp;
-                }
-            }
-            if (! retSzp)
-                return resp;
-            num_sect /= 2;      /* try half as many */
-            rqSz = num_sect * SG_SECTOR_SZ;
-        }
-    }
     else if (SG_HEAP_PAGE == mem_src) {
         int order, a_size;
         int resSz = rqSz;
@@ -2311,7 +2474,8 @@
         if (retSzp) *retSzp = resSz;
     }
     else
-        printk("sg_low_malloc: bad mem_src=%d, rqSz=%df\n", mem_src, rqSz);
+        printk(KERN_ERR "sg_low_malloc: bad mem_src=%d, rqSz=%df\n", 
+	       mem_src, rqSz);
     return resp;
 }
 
@@ -2330,29 +2494,20 @@
 	switch (*mem_srcp)
         {
         case SG_HEAP_PAGE:
-            l_ms = (size < PAGE_SIZE) ? SG_HEAP_POOL : SG_HEAP_PAGE;
+            l_ms = (size < PAGE_SIZE) ? SG_HEAP_KMAL : SG_HEAP_PAGE;
             resp = sg_low_malloc(size, low_dma, l_ms, 0);
             if (resp)
                 break;
             resp = sg_low_malloc(size, low_dma, l_ms, &size);
             if (! resp) {
-                l_ms = (SG_HEAP_POOL == l_ms) ? SG_HEAP_PAGE : SG_HEAP_POOL;
+                l_ms = (SG_HEAP_KMAL == l_ms) ? SG_HEAP_PAGE : SG_HEAP_KMAL;
                 resp = sg_low_malloc(size, low_dma, l_ms, &size);
-                if (! resp) {
-                    l_ms = SG_HEAP_KMAL;
-                    resp = sg_low_malloc(size, low_dma, l_ms, &size);
-                }
             }
             if (resp && retSzp) *retSzp = size;
             break;
         case SG_HEAP_KMAL:
-            l_ms = SG_HEAP_PAGE;
+            l_ms = SG_HEAP_KMAL; /* was SG_HEAP_PAGE */
             resp = sg_low_malloc(size, low_dma, l_ms, 0);
-            if (resp)
-                break;
-            l_ms = SG_HEAP_POOL;
-            resp = sg_low_malloc(size, low_dma, l_ms, &size);
-            if (resp && retSzp) *retSzp = size;
             break;
         default:
             SCSI_LOG_TIMEOUT(1, printk("sg_malloc: bad ms=%d\n", *mem_srcp));
@@ -2365,18 +2520,19 @@
     return resp;
 }
 
+static inline int sg_alloc_kiovec(int nr, struct kiobuf **bufp, int *szp)
+{
+#if SG_NEW_KIOVEC
+    return alloc_kiovec_sz(nr, bufp, szp);
+#else
+    return alloc_kiovec(nr, bufp);
+#endif
+}
+
 static void sg_low_free(char * buff, int size, int mem_src)
 {
     if (! buff) return;
     switch (mem_src) {
-    case SG_HEAP_POOL:
-	{
-	    int num_sect = size / SG_SECTOR_SZ;
-
-	    kfree(buff);
-	    sg_pool_secs_avail += num_sect;
-	}
-	break;
     case SG_HEAP_KMAL:
 	kfree(buff);    /* size not used */
 	break;
@@ -2392,7 +2548,7 @@
     case SG_USER_MEM:
 	break; /* nothing to do */
     default:
-	printk("sg_low_free: bad mem_src=%d, buff=0x%p, rqSz=%d\n",
+	printk(KERN_ERR "sg_low_free: bad mem_src=%d, buff=0x%p, rqSz=%d\n",
                mem_src, buff, size);
 	break;
     }
@@ -2408,14 +2564,13 @@
         sg_low_free(buff, size, mem_src);
 }
 
-static void sg_clr_srpnt(Scsi_Request * SRpnt)
+static inline void sg_free_kiovec(int nr, struct kiobuf **bufp, int *szp)
 {
-    SRpnt->sr_use_sg = 0;
-    SRpnt->sr_sglist_len = 0;
-    SRpnt->sr_bufflen = 0;
-    SRpnt->sr_buffer = NULL;
-    SRpnt->sr_underflow = 0;
-    SRpnt->sr_request.rq_dev = mk_kdev(0, 0);  /* "sg" _disowns_ command blk */
+#if SG_NEW_KIOVEC
+    free_kiovec_sz(nr, bufp, szp);
+#else
+    free_kiovec(nr, bufp);
+#endif
 }
 
 static int sg_ms_to_jif(unsigned int msecs)
@@ -2427,7 +2582,7 @@
 					       : (((int)msecs / 1000) * HZ);
 }
 
-static unsigned sg_jif_to_ms(int jifs)
+static inline unsigned sg_jif_to_ms(int jifs)
 {
     if (jifs <= 0)
 	return 0U;
@@ -2477,8 +2632,8 @@
     if (sg_dev_arr && (dev >= 0))
     {
 	read_lock_irqsave(&sg_dev_arr_lock, iflags);
-    if (dev < sg_template.dev_max)
-    	sdp = sg_dev_arr[dev];
+	if (dev < sg_template.dev_max)
+	    sdp = sg_dev_arr[dev];
 	read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
     }
     return sdp;
@@ -2671,7 +2826,7 @@
 {
     Sg_device * sdp;
     const sg_io_hdr_t * hp;
-    int j, max_dev;
+    int j, max_dev, new_interface;
 
     if (NULL == sg_dev_arr) {
 	PRINT_PROC("sg_dev_arr NULL, driver not initialized\n");
@@ -2680,8 +2835,7 @@
     max_dev = sg_last_dev();
     PRINT_PROC("dev_max(currently)=%d max_active_device=%d (origin 1)\n",
 	       sg_template.dev_max, max_dev);
-    PRINT_PROC(" sg_pool_secs_aval=%d def_reserved_size=%d\n",
-	       sg_pool_secs_avail, sg_big_buff);
+    PRINT_PROC(" def_reserved_size=%d\n", sg_big_buff);
     for (j = 0; j < max_dev; ++j) {
 	if ((sdp = sg_get_dev(j))) {
 	    Sg_fd * fp;
@@ -2717,8 +2871,10 @@
 			   (int)fp->keep_orphan, (int)fp->closed);
 		for (m = 0; (srp = sg_get_nth_request(fp, m)); ++m) {
 		    hp = &srp->header;
+		    new_interface = (hp->interface_id == '\0') ? 0 : 1;
 /* stop indenting so far ... */
-	PRINT_PROC(srp->res_used ? "     rb>> " :
+	PRINT_PROC(srp->res_used ? ((new_interface && 
+	    (SG_FLAG_MMAP_IO & hp->flags)) ? "     mmap>> " : "     rb>> ") :
 	    ((SG_INFO_DIRECT_IO_MASK & hp->info) ? "     dio>> " : "     "));
 	blen = srp->my_cmdp ? srp->my_cmdp->sr_bufflen : srp->data.bufflen;
 	usg = srp->my_cmdp ? srp->my_cmdp->sr_use_sg : srp->data.k_use_sg;
@@ -2728,8 +2884,8 @@
 	if (srp->done)
 	    PRINT_PROC(" dur=%d", hp->duration);
 	else
-	    PRINT_PROC(" t_o/elap=%d/%d", ((hp->interface_id == '\0') ?
-			sg_jif_to_ms(fp->timeout) : hp->timeout),
+	    PRINT_PROC(" t_o/elap=%d/%d", new_interface ? hp->timeout :
+			sg_jif_to_ms(fp->timeout),
 		  sg_jif_to_ms(hp->duration ? (jiffies - hp->duration) : 0));
 	PRINT_PROC("ms sgat=%d op=0x%02x\n", usg, (int)srp->data.cmd_opcode);
 /* reset indenting */
diff -u --recursive --new-file v2.5.2/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v2.5.2/linux/drivers/scsi/sr.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/scsi/sr.c	Thu Jan 17 13:59:33 2002
@@ -331,7 +331,7 @@
 
 	SCSI_LOG_HLQUEUE(2, printk("sr%d : %s %d/%ld 512 byte blocks.\n",
                                    devm,
-		   (SCpnt->request.cmd == WRITE) ? "writing" : "reading",
+		   (rq_data_dir(&SCpnt->request) == WRITE) ? "writing" : "reading",
 				 this_count, SCpnt->request.nr_sectors));
 
 	SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ?
diff -u --recursive --new-file v2.5.2/linux/drivers/sgi/char/graphics.c linux/drivers/sgi/char/graphics.c
--- v2.5.2/linux/drivers/sgi/char/graphics.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/sgi/char/graphics.c	Tue Jan 15 10:56:35 2002
@@ -231,7 +231,7 @@
 		/* FIXME: save graphics context here, dump it to rendering
 		 * node? */
 
-		remove_mapping(cards[board].g_user, vma->vm_start, vma->vm_end);
+		remove_mapping(vma, cards[board].g_user, vma->vm_start, vma->vm_end);
 	}
 
 	cards [board].g_user = current;
@@ -241,7 +241,7 @@
 
 	virt_add = address & PAGE_MASK;
 	phys_add = cards[board].g_regs + virt_add - vma->vm_start;
-	remap_page_range(virt_add, phys_add, PAGE_SIZE, vma->vm_page_prot);
+	remap_page_range(vma, virt_add, phys_add, PAGE_SIZE, vma->vm_page_prot);
 
 	pgd = pgd_offset(current->mm, address);
 	pmd = pmd_offset(pgd, address);
diff -u --recursive --new-file v2.5.2/linux/drivers/sgi/char/shmiq.c linux/drivers/sgi/char/shmiq.c
--- v2.5.2/linux/drivers/sgi/char/shmiq.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/sgi/char/shmiq.c	Tue Jan 15 10:56:35 2002
@@ -348,7 +348,7 @@
 	/* Init the shared memory input queue */
 	spin_unlock( &shmiqs [minor].shmiq_lock );
 	memset (shmiqs [minor].shmiq_vaddr, 0, size);
-	error = vmap_page_range (vma->vm_start, size, mem);
+	error = vmap_page_range (vma, vma->vm_start, size, mem);
 	return error;
 }
 
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/cmpci.c linux/drivers/sound/cmpci.c
--- v2.5.2/linux/drivers/sound/cmpci.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/sound/cmpci.c	Tue Jan 15 10:56:35 2002
@@ -1752,7 +1752,7 @@
 	if (size > (PAGE_SIZE << db->buforder))
 		goto out;
 	ret = -EINVAL;
-	if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
+	if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
 		goto out;
 	db->mapped = 1;
 	ret = 0;
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/cs4281/cs4281m.c linux/drivers/sound/cs4281/cs4281m.c
--- v2.5.2/linux/drivers/sound/cs4281/cs4281m.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/sound/cs4281/cs4281m.c	Tue Jan 15 10:56:35 2002
@@ -3145,7 +3145,7 @@
 	if (size > (PAGE_SIZE << db->buforder))
 		return -EINVAL;
 	if (remap_page_range
-	    (vma->vm_start, virt_to_phys(db->rawbuf), size,
+	    (vma, vma->vm_start, virt_to_phys(db->rawbuf), size,
 	     vma->vm_page_prot)) return -EAGAIN;
 	db->mapped = 1;
 
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/cs46xx.c linux/drivers/sound/cs46xx.c
--- v2.5.2/linux/drivers/sound/cs46xx.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/sound/cs46xx.c	Tue Jan 15 10:56:35 2002
@@ -2467,7 +2467,7 @@
 		ret = -EINVAL;
 		goto out;
 	}
-	if (remap_page_range(vma->vm_start, virt_to_phys(dmabuf->rawbuf),
+	if (remap_page_range(vma, vma->vm_start, virt_to_phys(dmabuf->rawbuf),
 			     size, vma->vm_page_prot))
 	{
 		ret = -EAGAIN;
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c
--- v2.5.2/linux/drivers/sound/es1370.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/sound/es1370.c	Tue Jan 15 10:56:35 2002
@@ -1373,7 +1373,7 @@
 		ret = -EINVAL;
 		goto out;
 	}
-	if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) {
+	if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) {
 		ret = -EAGAIN;
 		goto out;
 	}
@@ -1945,7 +1945,7 @@
 	if (size > (PAGE_SIZE << s->dma_dac1.buforder))
 		goto out;
 	ret = -EAGAIN;
-	if (remap_page_range(vma->vm_start, virt_to_phys(s->dma_dac1.rawbuf), size, vma->vm_page_prot))
+	if (remap_page_range(vma, vma->vm_start, virt_to_phys(s->dma_dac1.rawbuf), size, vma->vm_page_prot))
 		goto out;
 	s->dma_dac1.mapped = 1;
 	ret = 0;
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c
--- v2.5.2/linux/drivers/sound/es1371.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/sound/es1371.c	Tue Jan 15 10:56:35 2002
@@ -1562,7 +1562,7 @@
 		ret = -EINVAL;
 		goto out;
 	}
-	if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) {
+	if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) {
 		ret = -EAGAIN;
 		goto out;
 	}
@@ -2131,7 +2131,7 @@
 	if (size > (PAGE_SIZE << s->dma_dac1.buforder))
 		goto out;
 	ret = -EAGAIN;
-	if (remap_page_range(vma->vm_start, virt_to_phys(s->dma_dac1.rawbuf), size, vma->vm_page_prot))
+	if (remap_page_range(vma, vma->vm_start, virt_to_phys(s->dma_dac1.rawbuf), size, vma->vm_page_prot))
 		goto out;
 	s->dma_dac1.mapped = 1;
 	ret = 0;
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/esssolo1.c linux/drivers/sound/esssolo1.c
--- v2.5.2/linux/drivers/sound/esssolo1.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/sound/esssolo1.c	Tue Jan 15 10:56:35 2002
@@ -1245,7 +1245,7 @@
 	if (size > (PAGE_SIZE << db->buforder))
 		goto out;
 	ret = -EAGAIN;
-	if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
+	if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
 		goto out;
 	db->mapped = 1;
 	ret = 0;
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/i810_audio.c linux/drivers/sound/i810_audio.c
--- v2.5.2/linux/drivers/sound/i810_audio.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/sound/i810_audio.c	Tue Jan 15 10:56:35 2002
@@ -1559,7 +1559,7 @@
 	if (size > (PAGE_SIZE << dmabuf->buforder))
 		goto out;
 	ret = -EAGAIN;
-	if (remap_page_range(vma->vm_start, virt_to_phys(dmabuf->rawbuf),
+	if (remap_page_range(vma, vma->vm_start, virt_to_phys(dmabuf->rawbuf),
 			     size, vma->vm_page_prot))
 		goto out;
 	dmabuf->mapped = 1;
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/ite8172.c linux/drivers/sound/ite8172.c
--- v2.5.2/linux/drivers/sound/ite8172.c	Thu Oct 25 13:53:52 2001
+++ linux/drivers/sound/ite8172.c	Tue Jan 15 10:56:35 2002
@@ -1106,7 +1106,7 @@
 	unlock_kernel();
 	return -EINVAL;
     }
-    if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf),
+    if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf),
 			 size, vma->vm_page_prot)) {
 	unlock_kernel();
 	return -EAGAIN;
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/maestro.c linux/drivers/sound/maestro.c
--- v2.5.2/linux/drivers/sound/maestro.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/sound/maestro.c	Tue Jan 15 10:56:35 2002
@@ -2510,7 +2510,7 @@
 	if (size > (PAGE_SIZE << db->buforder))
 		goto out;
 	ret = -EAGAIN;
-	if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
+	if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
 		goto out;
 	db->mapped = 1;
 	ret = 0;
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/maestro3.c linux/drivers/sound/maestro3.c
--- v2.5.2/linux/drivers/sound/maestro3.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/sound/maestro3.c	Tue Jan 15 10:56:35 2002
@@ -1555,7 +1555,7 @@
      * ask Jeff what the hell I'm doing wrong.
      */
     ret = -EAGAIN;
-    if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
+    if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
         goto out;
 
     db->mapped = 1;
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/rme96xx.c linux/drivers/sound/rme96xx.c
--- v2.5.2/linux/drivers/sound/rme96xx.c	Thu Oct 25 13:53:52 2001
+++ linux/drivers/sound/rme96xx.c	Tue Jan 15 10:56:35 2002
@@ -1411,14 +1411,14 @@
 	if (vma->vm_flags & VM_WRITE) {
 		if (!s->started) rme96xx_startcard(s,1);
 
-		if (remap_page_range(vma->vm_start, virt_to_phys(s->playbuf + dma->outoffset*RME96xx_DMA_MAX_SIZE), size, vma->vm_page_prot)) {
+		if (remap_page_range(vma, vma->vm_start, virt_to_phys(s->playbuf + dma->outoffset*RME96xx_DMA_MAX_SIZE), size, vma->vm_page_prot)) {
 			unlock_kernel();
 			return -EAGAIN;
 		}
 	} 
 	else if (vma->vm_flags & VM_READ) {
 		if (!s->started) rme96xx_startcard(s,1);
-		if (remap_page_range(vma->vm_start, virt_to_phys(s->playbuf + dma->inoffset*RME96xx_DMA_MAX_SIZE), size, vma->vm_page_prot)) {
+		if (remap_page_range(vma, vma->vm_start, virt_to_phys(s->playbuf + dma->inoffset*RME96xx_DMA_MAX_SIZE), size, vma->vm_page_prot)) {
 			unlock_kernel();
 			return -EAGAIN;
 		}
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c
--- v2.5.2/linux/drivers/sound/sonicvibes.c	Sun Sep 30 12:26:08 2001
+++ linux/drivers/sound/sonicvibes.c	Tue Jan 15 10:56:35 2002
@@ -1549,7 +1549,7 @@
 	if (size > (PAGE_SIZE << db->buforder))
 		goto out;
 	ret = -EAGAIN;
-	if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
+	if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
 		goto out;
 	db->mapped = 1;
 	ret = 0;
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c
--- v2.5.2/linux/drivers/sound/soundcard.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/sound/soundcard.c	Tue Jan 15 10:56:35 2002
@@ -473,7 +473,7 @@
 	if (size != dmap->bytes_in_use) {
 		printk(KERN_WARNING "Sound: mmap() size = %ld. Should be %d\n", size, dmap->bytes_in_use);
 	}
-	if (remap_page_range(vma->vm_start, virt_to_phys(dmap->raw_buf),
+	if (remap_page_range(vma, vma->vm_start, virt_to_phys(dmap->raw_buf),
 		vma->vm_end - vma->vm_start,
 		vma->vm_page_prot)) {
 		unlock_kernel();
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/trident.c linux/drivers/sound/trident.c
--- v2.5.2/linux/drivers/sound/trident.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/sound/trident.c	Tue Jan 15 10:56:35 2002
@@ -2074,7 +2074,7 @@
 	if (size > (PAGE_SIZE << dmabuf->buforder))
 		goto out;
 	ret = -EAGAIN;
-	if (remap_page_range(vma->vm_start, virt_to_phys(dmabuf->rawbuf),
+	if (remap_page_range(vma, vma->vm_start, virt_to_phys(dmabuf->rawbuf),
 			     size, vma->vm_page_prot))
 		goto out;
 	dmabuf->mapped = 1;
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/via82cxxx_audio.c linux/drivers/sound/via82cxxx_audio.c
--- v2.5.2/linux/drivers/sound/via82cxxx_audio.c	Tue Dec 18 14:56:38 2001
+++ linux/drivers/sound/via82cxxx_audio.c	Tue Jan 15 13:53:51 2002
@@ -1995,7 +1995,7 @@
 	/* just to be a nice neighbor */
 	/* Thomas Sailer:
 	 * But also to ourselves, release semaphore if we do so */
-	if (current->need_resched) {
+	if (need_resched()) {
 		up(&card->syscall_sem);
 		schedule ();
 		ret = via_syscall_down (card, nonblock);
@@ -2171,7 +2171,7 @@
 	/* just to be a nice neighbor */
 	/* Thomas Sailer:
 	 * But also to ourselves, release semaphore if we do so */
-	if (current->need_resched) {
+	if (need_resched()) {
 		up(&card->syscall_sem);
 		schedule ();
 		ret = via_syscall_down (card, nonblock);
diff -u --recursive --new-file v2.5.2/linux/drivers/sound/ymfpci.c linux/drivers/sound/ymfpci.c
--- v2.5.2/linux/drivers/sound/ymfpci.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/sound/ymfpci.c	Tue Jan 15 10:56:35 2002
@@ -1525,7 +1525,7 @@
 	size = vma->vm_end - vma->vm_start;
 	if (size > (PAGE_SIZE << dmabuf->buforder))
 		return -EINVAL;
-	if (remap_page_range(vma->vm_start, virt_to_phys(dmabuf->rawbuf),
+	if (remap_page_range(vma, vma->vm_start, virt_to_phys(dmabuf->rawbuf),
 			     size, vma->vm_page_prot))
 		return -EAGAIN;
 	dmabuf->mapped = 1;
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/audio.c linux/drivers/usb/audio.c
--- v2.5.2/linux/drivers/usb/audio.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/audio.c	Tue Jan 15 10:56:35 2002
@@ -510,7 +510,7 @@
 	return 0;
 }
 
-static int dmabuf_mmap(struct dmabuf *db, unsigned long start, unsigned long size, pgprot_t prot)
+static int dmabuf_mmap(struct vm_area_struct *vma, struct dmabuf *db, unsigned long start, unsigned long size, pgprot_t prot)
 {
 	unsigned int nr;
 
@@ -522,7 +522,7 @@
 			return -EINVAL;
 	db->mapped = 1;
 	for(nr = 0; nr < size; nr++) {
-		if (remap_page_range(start, virt_to_phys(db->sgbuf[nr]), PAGE_SIZE, prot))
+		if (remap_page_range(vma, start, virt_to_phys(db->sgbuf[nr]), PAGE_SIZE, prot))
 			return -EAGAIN;
 		start += PAGE_SIZE;
 	}
@@ -2341,7 +2341,7 @@
 	if (vma->vm_pgoff != 0)
 		goto out;
 
-	ret = dmabuf_mmap(db,  vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot);
+	ret = dmabuf_mmap(vma, db,  vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot);
 out:
 	unlock_kernel();
 	return ret;
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/hcd/ehci-hcd.c linux/drivers/usb/hcd/ehci-hcd.c
--- v2.5.2/linux/drivers/usb/hcd/ehci-hcd.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/hcd/ehci-hcd.c	Thu Jan 17 14:06:53 2002
@@ -70,9 +70,15 @@
  *	Brad Hards
  *	Rory Bolt
  *	...
+ *
+ * HISTORY:
+ * 2002-01-14	Minor cleanup; version synch.
+ * 2002-01-08	Fix roothub handoff of FS/LS to companion controllers.
+ * 2002-01-04	Control/Bulk queuing behaves.
+ * 2001-12-12	Initial patch version for Linux 2.5.1 kernel.
  */
 
-#define DRIVER_VERSION "$Revision: 0.25 $"
+#define DRIVER_VERSION "$Revision: 0.26 $"
 #define DRIVER_AUTHOR "David Brownell"
 #define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
 
@@ -97,9 +103,6 @@
 static int log2_irq_thresh = 0;		// 0 to 6
 MODULE_PARM (log2_irq_thresh, "i");
 MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes");
-
-/* Some A steppings of the NEC controller need soft retries */
-//#define	EHCI_SOFT_RETRIES	5	/* after CERR-induced fault */
 
 #define	INTR_MASK (STS_IAA | STS_FATAL | STS_ERR | STS_INT)
 
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/hcd/ehci-hub.c linux/drivers/usb/hcd/ehci-hub.c
--- v2.5.2/linux/drivers/usb/hcd/ehci-hub.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/hcd/ehci-hub.c	Thu Jan 17 14:06:53 2002
@@ -82,11 +82,12 @@
 	for (i = 0; i < ports; i++) {
 		temp = readl (&ehci->regs->port_status [i]);
 		if (temp & PORT_OWNER) {
-			// get disconnected ports back if no companion driver
-			if (temp & PORT_CONNECT)
-				continue;
-			temp &= ~(PORT_OWNER|PORT_CSC);
-			writel (temp, &ehci->regs->port_status [i]);
+			/* don't report this in GetPortStatus */
+			if (temp & PORT_CSC) {
+				temp &= ~PORT_CSC;
+				writel (temp, &ehci->regs->port_status [i]);
+			}
+			continue;
 		}
 		if (!(temp & PORT_CONNECT))
 			ehci->reset_done [i] = 0;
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/hcd/ehci-q.c linux/drivers/usb/hcd/ehci-q.c
--- v2.5.2/linux/drivers/usb/hcd/ehci-q.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/hcd/ehci-q.c	Thu Jan 17 14:06:53 2002
@@ -883,11 +883,10 @@
 		/* can't get here without STS_ASS set */
 		if (ehci->hcd.state != USB_STATE_HALT) {
 			if (cmd & CMD_PSE)
-				writel (cmd & __constant_cpu_to_le32 (~CMD_ASE),
-					&ehci->regs->command);
+				writel (cmd & ~CMD_ASE, &ehci->regs->command);
 			else {
 				ehci_ready (ehci);
-				while (!(readl (&ehci->regs->status) & STS_ASS))
+				while (readl (&ehci->regs->status) & STS_ASS)
 					udelay (100);
 			}
 		}
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/hcd/ehci-sched.c linux/drivers/usb/hcd/ehci-sched.c
--- v2.5.2/linux/drivers/usb/hcd/ehci-sched.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/hcd/ehci-sched.c	Thu Jan 17 14:06:53 2002
@@ -381,7 +381,7 @@
 			vdbg ("qh %p usecs %d period %d starting frame %d.%d",
 				qh, qh->usecs, period, frame, uframe);
 			do {
-				if (unlikely ((long)ehci->pshadow [frame].ptr)) {
+				if (unlikely (ehci->pshadow [frame].ptr != 0)) {
 // FIXME -- just link to the end, before any qh with a shorter period,
 // AND handle it already being (implicitly) linked into this frame
 					BUG ();
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/hcd.c linux/drivers/usb/hcd.c
--- v2.5.2/linux/drivers/usb/hcd.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/hcd.c	Thu Jan 17 14:06:53 2002
@@ -1081,20 +1081,20 @@
 	if (!urb)
 		return -EINVAL;
 
-	// FIXME:  add some explicit records to flag the
-	// state where the URB is "in periodic completion".
-	// Workaround is for driver to set the urb status
-	// to "-EINPROGRESS", so it can get through here
-	// and unlink from the completion handler.
-
 	/*
 	 * we contend for urb->status with the hcd core,
 	 * which changes it while returning the urb.
+	 *
+	 * Caller guaranteed that the urb pointer hasn't been freed, and
+	 * that it was submitted.  But as a rule it can't know whether or
+	 * not it's already been unlinked ... so we respect the reversed
+	 * lock sequence needed for the usb_hcd_giveback_urb() code paths
+	 * (urb lock, then hcd_data_lock) in case some other CPU is now
+	 * unlinking it.
 	 */
 	spin_lock_irqsave (&urb->lock, flags);
-	if (!urb->hcpriv
-			|| urb->status != -EINPROGRESS
-			|| urb->transfer_flags & USB_TIMEOUT_KILLED) {
+	spin_lock (&hcd_data_lock);
+	if (!urb->hcpriv || urb->transfer_flags & USB_TIMEOUT_KILLED) {
 		retval = -EINVAL;
 		goto done;
 	}
@@ -1103,6 +1103,8 @@
 		retval = -ENODEV;
 		goto done;
 	}
+
+	/* giveback clears dev; non-null means it's linked at this level */
 	dev = urb->dev->hcpriv;
 	hcd = urb->dev->bus->hcpriv;
 	if (!dev || !hcd) {
@@ -1110,6 +1112,27 @@
 		goto done;
 	}
 
+	/* For non-periodic transfers, any status except -EINPROGRESS means
+	 * the HCD has already started to unlink this URB from the hardware.
+	 * In that case, there's no more work to do.
+	 *
+	 * For periodic transfers, this is the only way to trigger unlinking
+	 * from the hardware.  Since we (currently) overload urb->status to
+	 * tell the driver to unlink, error status might get clobbered ...
+	 * unless that transfer hasn't yet restarted.  One such case is when
+	 * the URB gets unlinked from its completion handler.
+	 *
+	 * FIXME use an URB_UNLINKED flag to match URB_TIMEOUT_KILLED
+	 */
+	switch (usb_pipetype (urb->pipe)) {
+	case PIPE_CONTROL:
+	case PIPE_BULK:
+		if (urb->status != -EINPROGRESS) {
+			retval = 0;
+			goto done;
+		}
+	}
+
 	/* maybe set up to block on completion notification */
 	if ((urb->transfer_flags & USB_TIMEOUT_KILLED))
 		urb->status = -ETIMEDOUT;
@@ -1130,6 +1153,7 @@
 		/* asynchronous unlink */
 		urb->status = -ECONNRESET;
 	}
+	spin_unlock (&hcd_data_lock);
 	spin_unlock_irqrestore (&urb->lock, flags);
 
 	if (urb == (struct urb *) hcd->rh_timer.data) {
@@ -1154,6 +1178,7 @@
 	}
 	goto bye;
 done:
+	spin_unlock (&hcd_data_lock);
 	spin_unlock_irqrestore (&urb->lock, flags);
 bye:
 	if (retval)
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/hpusbscsi.c linux/drivers/usb/hpusbscsi.c
--- v2.5.2/linux/drivers/usb/hpusbscsi.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/hpusbscsi.c	Thu Jan 17 14:06:53 2002
@@ -272,7 +272,7 @@
 	if (!srb->bufflen) {
 		usb_callback = simple_command_callback;
 	} else {
-        	if (srb->use_sg) {
+        	if (likely(srb->use_sg)) {
 			usb_callback = scatter_gather_callback;
 			hpusbscsi->fragment = 0;
 		} else {
@@ -288,10 +288,6 @@
 
 
 	TRACE_STATE;
-	if (hpusbscsi->state != HP_STATE_FREE) {
-		printk(KERN_CRIT"hpusbscsi - Ouch: queueing violation!\n");
-		return 1; /* This must not happen */
-	}
 
         /* We zero the sense buffer to avoid confusing user space */
         memset(srb->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
@@ -313,10 +309,10 @@
 	hpusbscsi->srb = srb;
 
 	res = usb_submit_urb(&hpusbscsi->dataurb);
-	if (res) {
+	if (unlikely(res)) {
 		hpusbscsi->state = HP_STATE_FREE;
 		TRACE_STATE;
-		if (callback) {
+		if (likely(callback != NULL)) {
 			srb->result = DID_ERROR;
 			callback(srb);
 		}
@@ -355,7 +351,7 @@
 
 static void handle_usb_error (struct hpusbscsi *hpusbscsi)
 {
-	if (hpusbscsi->scallback != NULL) {
+	if (likely(hpusbscsi->scallback != NULL)) {
 		hpusbscsi->srb->result = DID_ERROR;
 		hpusbscsi->scallback(hpusbscsi->srb);
 	}
@@ -367,8 +363,8 @@
 	struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
 
 DEBUG("Getting status byte %d \n",hpusbscsi->scsi_state_byte);
-	if(u->status < 0) {
-                if (hpusbscsi->state != HP_STATE_FREE)
+	if(unlikely(u->status < 0)) {
+                if (likely(hpusbscsi->state != HP_STATE_FREE))
                         handle_usb_error(hpusbscsi);
 		return;
 	}
@@ -402,7 +398,7 @@
 static void simple_command_callback(struct urb *u)
 {
 	struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
-	if (u->status<0) {
+	if (unlikely(u->status<0)) {
 		handle_usb_error(hpusbscsi);
 		return;
         }
@@ -411,7 +407,7 @@
 	        TRACE_STATE;
 		hpusbscsi->state = HP_STATE_WAIT;
 	} else {
-		if (hpusbscsi->scallback != NULL)
+		if (likely(hpusbscsi->scallback != NULL))
 			hpusbscsi->scallback(hpusbscsi->srb);
 		hpusbscsi->state = HP_STATE_FREE;
 	TRACE_STATE;
@@ -426,7 +422,7 @@
         int res;
 
         DEBUG("Going through scatter/gather\n");
-        if (u->status < 0) {
+        if (unlikely(u->status < 0)) {
                 handle_usb_error(hpusbscsi);
                 return;
         }
@@ -452,7 +448,7 @@
         );
 
         res = usb_submit_urb(u);
-        if (res)
+        if (unlikely(res))
                 hpusbscsi->state = HP_STATE_ERROR;
 	TRACE_STATE;
 }
@@ -461,20 +457,20 @@
 {
 	struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
 
-        if (u->status < 0) {
+        if (unlikely(u->status < 0)) {
                 handle_usb_error(hpusbscsi);
                 return;
         }
         DEBUG("Data transfer done\n");
 	TRACE_STATE;
 	if (hpusbscsi->state != HP_STATE_PREMATURE) {
-		if (u->status < 0)
+		if (unlikely(u->status < 0))
 			hpusbscsi->state = HP_STATE_ERROR;
 		else
 			hpusbscsi->state = HP_STATE_WAIT;
 		TRACE_STATE;
 	} else {
-		if (hpusbscsi->scallback != NULL)
+		if (likely(hpusbscsi->scallback != NULL))
 			hpusbscsi->scallback(hpusbscsi->srb);
 		hpusbscsi->state = HP_STATE_FREE;
 	}
@@ -485,7 +481,7 @@
 	struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
 	int res;
 
-	if (u->status<0) {
+	if (unlikely(u->status<0)) {
                 handle_usb_error(hpusbscsi);
 		return;
         }
@@ -501,7 +497,7 @@
 	);
 
 	res = usb_submit_urb(u);
-	if (res) {
+	if (unlikely(res)) {
                 handle_usb_error(hpusbscsi);
 		return;
         }
@@ -510,10 +506,11 @@
 		hpusbscsi->state = HP_STATE_WORKING;
 	TRACE_STATE;
 	} else {
-		if (hpusbscsi->scallback != NULL)
+		if (likely(hpusbscsi->scallback != NULL))
 			hpusbscsi->scallback(hpusbscsi->srb);
 		hpusbscsi->state = HP_STATE_FREE;
 	TRACE_STATE;
 	}
 }
+
 
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/hub.c linux/drivers/usb/hub.c
--- v2.5.2/linux/drivers/usb/hub.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/hub.c	Thu Jan 17 14:06:53 2002
@@ -557,6 +557,10 @@
 		dbg("port %d, portstatus %x, change %x, %s", port + 1,
 			portstatus, portchange, portspeed (portstatus));
 
+		/* Device went away? */
+		if (!(portstatus & USB_PORT_STAT_CONNECTION))
+			return 1;
+
 		/* bomb out completely if something weird happened */
 		if ((portchange & USB_PORT_STAT_C_CONNECTION))
 			return -1;
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/microtek.c linux/drivers/usb/microtek.c
--- v2.5.2/linux/drivers/usb/microtek.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/microtek.c	Thu Jan 17 14:06:53 2002
@@ -320,11 +320,6 @@
 
 #endif
 
-
-/* static inline int mts_is_aborting(struct mts_desc* desc) {
-	return (atomic_read(&desc->context.do_abort));
-}  */
-
 static inline void mts_urb_abort(struct mts_desc* desc) {
 	MTS_DEBUG_GOT_HERE();
 	mts_debug_dump(desc);
@@ -504,7 +499,7 @@
 	transfer->status = 0;
 
 	res = usb_submit_urb( transfer );
-	if ( res ) {
+	if ( unlikely(res) ) {
 		MTS_INT_ERROR( "could not submit URB! Error was %d\n",(int)res );
 		context->srb->result = DID_ERROR << 16;
 		mts_transfer_cleanup(transfer);
@@ -518,7 +513,7 @@
 {
 	MTS_INT_INIT();
 
-	if ( context->final_callback )
+	if ( likely(context->final_callback != NULL) )
 		context->final_callback(context->srb);
 
 }
@@ -556,7 +551,7 @@
 
 	if ( context->data_length != transfer->actual_length ) {
 		context->srb->resid = context->data_length - transfer->actual_length;
-	} else if ( transfer->status ) {
+	} else if ( unlikely(transfer->status) ) {
 		context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
 	}
 
@@ -571,7 +566,7 @@
 {
 	MTS_INT_INIT();
 
-	if ( transfer->status ) {
+	if ( unlikely(transfer->status) ) {
 	        if (transfer->status == -ENOENT) {
 		        /* We are being killed */
 			MTS_DEBUG_GOT_HERE();
@@ -605,7 +600,7 @@
 	
 	MTS_DEBUG("Processing fragment %d of %d\n", context->fragment,context->srb->use_sg);
 
-	if (transfer->status) {
+	if (unlikely(transfer->status)) {
                 context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
 		mts_transfer_cleanup(transfer);
         }
@@ -703,7 +698,7 @@
 
 		srb->result = DID_BAD_TARGET << 16;
 
-		if(callback)
+		if(likely(callback != NULL))
 			callback(srb);
 
 		goto out;
@@ -725,11 +720,11 @@
 	
 	res=usb_submit_urb(&desc->urb);
 
-	if(res){
+	if(unlikely(res)){
 		MTS_ERROR("error %d submitting URB\n",(int)res);
 		srb->result = DID_ERROR << 16;
 
-		if(callback)
+		if(likely(callback != NULL))
 			callback(srb);
 
 	}
@@ -1061,4 +1056,5 @@
 MODULE_AUTHOR( DRIVER_AUTHOR );
 MODULE_DESCRIPTION( DRIVER_DESC );
 MODULE_LICENSE("GPL");
+
 
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/ov511.c linux/drivers/usb/ov511.c
--- v2.5.2/linux/drivers/usb/ov511.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/ov511.c	Tue Jan 15 10:56:35 2002
@@ -5552,7 +5552,7 @@
 }
 
 static int 
-ov511_mmap(struct video_device *vdev, const char *adr, unsigned long size)
+ov511_mmap(struct vm_area_struct *vma, struct video_device *vdev, const char *adr, unsigned long size)
 {
 	struct usb_ov511 *ov511 = vdev->priv;
 	unsigned long start = (unsigned long)adr;
@@ -5574,7 +5574,7 @@
 	pos = (unsigned long)ov511->fbuf;
 	while (size > 0) {
 		page = kvirt_to_pa(pos);
-		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
+		if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
 			up(&ov511->lock);
 			return -EAGAIN;
 		}
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/pwc-if.c linux/drivers/usb/pwc-if.c
--- v2.5.2/linux/drivers/usb/pwc-if.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/pwc-if.c	Tue Jan 15 10:56:35 2002
@@ -125,7 +125,7 @@
 static long pwc_video_write(struct video_device *vdev, const char *buf, unsigned long count, int noblock);
 static unsigned int pwc_video_poll(struct video_device *vdev, struct file *file, poll_table *wait);
 static int  pwc_video_ioctl(struct video_device *vdev, unsigned int cmd, void *arg);
-static int  pwc_video_mmap(struct video_device *dev, const char *adr, unsigned long size);
+static int  pwc_video_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr, unsigned long size);
 
 static struct video_device pwc_template = {
 	owner:		THIS_MODULE,
@@ -1580,7 +1580,7 @@
 	return 0;
 }	
 
-static int pwc_video_mmap(struct video_device *vdev, const char *adr, unsigned long size)
+static int pwc_video_mmap(struct vm_area_struct *vma, struct video_device *vdev, const char *adr, unsigned long size)
 {
 	struct pwc_device *pdev;
 	unsigned long start = (unsigned long)adr;
@@ -1593,7 +1593,7 @@
 	pos = (unsigned long)pdev->image_data;
 	while (size > 0) {
 		page = kvirt_to_pa(pos);
-		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
+		if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
 			return -EAGAIN;
 
 		start += PAGE_SIZE;
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/se401.c linux/drivers/usb/se401.c
--- v2.5.2/linux/drivers/usb/se401.c	Fri Sep 14 14:27:10 2001
+++ linux/drivers/usb/se401.c	Tue Jan 15 10:56:35 2002
@@ -1354,7 +1354,7 @@
 	return realcount;
 }
 
-static int se401_mmap(struct video_device *dev, const char *adr,
+static int se401_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr,
         unsigned long size)
 {
 	struct usb_se401 *se401 = (struct usb_se401 *)dev;
@@ -1374,7 +1374,7 @@
 	pos = (unsigned long)se401->fbuf;
 	while (size > 0) {
 		page = kvirt_to_pa(pos);
-		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
+		if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
 			up(&se401->lock);
 			return -EAGAIN;
 		}
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/serial/ir-usb.c linux/drivers/usb/serial/ir-usb.c
--- v2.5.2/linux/drivers/usb/serial/ir-usb.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/serial/ir-usb.c	Thu Jan 17 14:06:53 2002
@@ -2,6 +2,7 @@
  * USB IR Dongle driver
  *
  *	Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ *	Copyright (C) 2002 Gary Brubaker (xavyer@ix.netcom.com)
  *
  *	This program is free software; you can redistribute it and/or modify
  *	it under the terms of the GNU General Public License as published by
@@ -20,6 +21,12 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
+ * 2002_Jan_14  gb
+ *	Added module parameter to force specific number of XBOFs.
+ *	Added ir_xbof_change().
+ *	Reorganized read_bulk_callback error handling.
+ *	Switched from FILL_BULK_URB() to usb_fill_bulk_urb().
+ *
  * 2001_Nov_08  greg kh
  *	Changed the irda_usb_find_class_desc() function based on comments and
  *	code from Martin Diehl.
@@ -62,13 +69,15 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.3"
+#define DRIVER_VERSION "v0.4"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>"
 #define DRIVER_DESC "USB IR Dongle driver"
 
 /* if overridden by the user, then use their value for the size of the read and
  * write urbs */
 static int buffer_size = 0;
+/* if overridden by the user, then use the specified number of XBOFs */
+static int xbof = -1;
 
 static int  ir_startup (struct usb_serial *serial);
 static int  ir_open (struct usb_serial_port *port, struct file *filep);
@@ -78,6 +87,9 @@
 static void ir_read_bulk_callback (struct urb *urb);
 static void ir_set_termios (struct usb_serial_port *port, struct termios *old_termios);
 
+static u8 ir_baud = 0;
+static u8 ir_xbof = 0;
+static u8 ir_add_bof = 0;
 
 static __devinitdata struct usb_device_id id_table [] = {
 	{ USB_DEVICE(0x050f, 0x0180) },		/* KC Technology, KC-180 */
@@ -148,14 +160,16 @@
 			USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
 			0, ifnum, desc, sizeof(*desc), MSECS_TO_JIFFIES(500));
 	
-	dbg(__FUNCTION__ " -  ret=%d", ret);
+	dbg("%s -  ret=%d", __FUNCTION__, ret);
 	if (ret < sizeof(*desc)) {
-		dbg(__FUNCTION__ " - class descriptor read %s (%d)",
-				(ret<0) ? "failed" : "too short", ret);
+		dbg("%s - class descriptor read %s (%d)",
+				__FUNCTION__, 
+				(ret<0) ? "failed" : "too short",
+				ret);
 		goto error;
 	}
 	if (desc->bDescriptorType != USB_DT_IRDA) {
-		dbg(__FUNCTION__ " - bad class descriptor type");
+		dbg("%s - bad class descriptor type", __FUNCTION__);
 		goto error;
 	}
 	
@@ -166,6 +180,28 @@
 	return NULL;
 }
 
+
+static u8 ir_xbof_change(u8 xbof)
+{
+	u8 result;
+	/* reference irda-usb.c */
+	switch(xbof) {
+		case 48: result = 0x10; break;
+		case 28:
+		case 24: result = 0x20; break;
+		default:
+		case 12: result = 0x30; break;
+		case  5:
+		case  6: result = 0x40; break;
+		case  3: result = 0x50; break;
+		case  2: result = 0x60; break;
+		case  1: result = 0x70; break;
+		case  0: result = 0x80; break;
+	}
+	return(result);
+}
+
+
 static int ir_startup (struct usb_serial *serial)
 {
 	struct irda_class_desc *irda_desc;
@@ -175,16 +211,30 @@
 		err ("IRDA class descriptor not found, device not bound");
 		return -ENODEV;
 	}
-	dbg (__FUNCTION__" - Baud rates supported: %s%s%s%s%s%s%s%s%s",
-	     (irda_desc->wBaudRate & 0x0001) ? "2400 " : "",
-	     irda_desc->wBaudRate & 0x0002 ? "9600 " : "",
-	     irda_desc->wBaudRate & 0x0004 ? "19200 " : "",
-	     irda_desc->wBaudRate & 0x0008 ? "38400 " : "",
-	     irda_desc->wBaudRate & 0x0010 ? "57600 " : "",
-	     irda_desc->wBaudRate & 0x0020 ? "115200 " : "",
-	     irda_desc->wBaudRate & 0x0040 ? "576000 " : "",
-	     irda_desc->wBaudRate & 0x0080 ? "1152000 " : "",
-	     irda_desc->wBaudRate & 0x0100 ? "4000000 " : "");
+
+	dbg ("%s - Baud rates supported:%s%s%s%s%s%s%s%s%s",
+		__FUNCTION__,
+		(irda_desc->wBaudRate & 0x0001) ? " 2400"    : "",
+		(irda_desc->wBaudRate & 0x0002) ? " 9600"    : "",
+		(irda_desc->wBaudRate & 0x0004) ? " 19200"   : "",
+		(irda_desc->wBaudRate & 0x0008) ? " 38400"   : "",
+		(irda_desc->wBaudRate & 0x0010) ? " 57600"   : "",
+		(irda_desc->wBaudRate & 0x0020) ? " 115200"  : "",
+		(irda_desc->wBaudRate & 0x0040) ? " 576000"  : "",
+		(irda_desc->wBaudRate & 0x0080) ? " 1152000" : "",
+		(irda_desc->wBaudRate & 0x0100) ? " 4000000" : "");
+
+	switch( irda_desc->bmAdditionalBOFs ) {
+		case 0x01: ir_add_bof = 48; break;
+		case 0x02: ir_add_bof = 24; break;
+		case 0x04: ir_add_bof = 12; break;
+		case 0x08: ir_add_bof =  6; break;
+		case 0x10: ir_add_bof =  3; break;
+		case 0x20: ir_add_bof =  2; break;
+		case 0x40: ir_add_bof =  1; break;
+		case 0x80: ir_add_bof =  0; break;
+		default:
+	}
 
 	kfree (irda_desc);
 
@@ -200,7 +250,7 @@
 	if (port_paranoia_check (port, __FUNCTION__))
 		return -ENODEV;
 	
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	down (&port->sem);
 	
@@ -211,7 +261,7 @@
 			/* override the default buffer sizes */
 			buffer = kmalloc (buffer_size, GFP_KERNEL);
 			if (!buffer) {
-				err (__FUNCTION__ " - out of memory.");
+				err ("%s - out of memory.", __FUNCTION__);
 				return -ENOMEM;
 			}
 			kfree (port->read_urb->transfer_buffer);
@@ -220,7 +270,7 @@
 
 			buffer = kmalloc (buffer_size, GFP_KERNEL);
 			if (!buffer) {
-				err (__FUNCTION__ " - out of memory.");
+				err ("%s - out of memory.", __FUNCTION__);
 				return -ENOMEM;
 			}
 			kfree (port->write_urb->transfer_buffer);
@@ -230,13 +280,18 @@
 		}
 
 		/* Start reading from the device */
-		FILL_BULK_URB(port->read_urb, serial->dev, 
-			      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
-			      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
-			      ir_read_bulk_callback, port);
+		usb_fill_bulk_urb (
+			port->read_urb,
+			serial->dev, 
+			usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+			port->read_urb->transfer_buffer,
+			port->read_urb->transfer_buffer_length,
+			ir_read_bulk_callback,
+			port);
+		port->read_urb->transfer_flags = USB_QUEUE_BULK;
 		result = usb_submit_urb(port->read_urb);
 		if (result)
-			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+			err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
 	}
 	
 	up (&port->sem);
@@ -251,7 +306,7 @@
 	if (port_paranoia_check (port, __FUNCTION__))
 		return;
 	
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 			 
 	serial = get_usb_serial (port, __FUNCTION__);
 	if (!serial)
@@ -276,11 +331,12 @@
 {
 	unsigned char *transfer_buffer;
 	int result;
+	int transfer_size;
 
-	dbg(__FUNCTION__ " - port = %d, count = %d", port->number, count);
+	dbg("%s - port = %d, count = %d", __FUNCTION__, port->number, count);
 
 	if (!port->tty) {
-		err (__FUNCTION__ " - no tty???");
+		err ("%s - no tty???", __FUNCTION__);
 		return 0;
 	}
 
@@ -288,37 +344,49 @@
 		return 0;
 
 	if (port->write_urb->status == -EINPROGRESS) {
-		dbg (__FUNCTION__ " - already writing");
+		dbg ("%s - already writing", __FUNCTION__);
 		return 0;
 	}
 
+	transfer_buffer = port->write_urb->transfer_buffer;
+	transfer_size = min(count, port->bulk_out_size - 1);
+
 	/*
-	 * The first byte of the packet we send to the device contains a BOD
-	 * and baud rate change.  So we set it to 0.
+	 * The first byte of the packet we send to the device contains an
+	 * inband header which indicates an additional number of BOFs and
+	 * a baud rate change.
+	 *
 	 * See section 5.4.2.2 of the USB IrDA spec.
 	 */
-	transfer_buffer = port->write_urb->transfer_buffer;
-	count = min (port->bulk_out_size-1, count);
+	*transfer_buffer = ir_xbof | ir_baud;
+	++transfer_buffer;
+
 	if (from_user) {
-		if (copy_from_user (&transfer_buffer[1], buf, count))
+		if (copy_from_user (transfer_buffer, buf, transfer_size))
 			return -EFAULT;
 	} else {
-		memcpy (&transfer_buffer[1], buf, count);
+		memcpy (transfer_buffer, buf, transfer_size);
 	}
 
-	/* use 12 XBOF's as default */
-	transfer_buffer[0] = 0x30;
-
-	usb_serial_debug_data (__FILE__, __FUNCTION__, count+1, transfer_buffer);
+	usb_fill_bulk_urb (
+		port->write_urb,
+		port->serial->dev,
+		usb_sndbulkpipe(port->serial->dev,
+			port->bulk_out_endpointAddress),
+		port->write_urb->transfer_buffer,
+		transfer_size + 1,
+		ir_write_bulk_callback,
+		port);
+
+	port->write_urb->transfer_flags
+		= USB_QUEUE_BULK
+		| USB_ZERO_PACKET;
 
-	port->write_urb->transfer_buffer_length = count + 1;
-	port->write_urb->dev = port->serial->dev;
-	port->write_urb->transfer_flags |= USB_ZERO_PACKET;
 	result = usb_submit_urb (port->write_urb);
 	if (result)
-		err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+		err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
 	else
-		result = count;
+		result = transfer_size;
 
 	return result;
 }
@@ -330,13 +398,19 @@
 	if (port_paranoia_check (port, __FUNCTION__))
 		return;
 	
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 	
 	if (urb->status) {
-		dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
+		dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
 		return;
 	}
 
+	usb_serial_debug_data (
+		__FILE__,
+		__FUNCTION__,
+		urb->actual_length,
+		urb->transfer_buffer);
+
 	queue_task(&port->tqueue, &tq_immediate);
 	mark_bh(IMMEDIATE_BH);
 	
@@ -354,34 +428,87 @@
 	if (port_paranoia_check (port, __FUNCTION__))
 		return;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	if (!serial) {
-		dbg(__FUNCTION__ " - bad serial pointer, exiting");
+		dbg("%s - bad serial pointer, exiting", __FUNCTION__);
 		return;
 	}
 
-	if (urb->status) {
-		dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+	if (!port->open_count) {
+		dbg("%s - port closed.", __FUNCTION__);
 		return;
 	}
 
-	usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+	switch (urb->status) {
+
+		case 0: /* Successful */
+
+			/*
+			 * The first byte of the packet we get from the device
+			 * contains a busy indicator and baud rate change.
+			 * See section 5.4.1.2 of the USB IrDA spec.
+			 */
+			if((*data & 0x0f) > 0) ir_baud = *data & 0x0f;
+
+			usb_serial_debug_data (
+				__FILE__,
+				__FUNCTION__,
+				urb->actual_length,
+				data);
+
+			/*
+			 * Bypass flip-buffers, and feed the ldisc directly
+			 * due to our potentally large buffer size.  Since we
+			 * used to set low_latency, this is exactly what the
+			 * tty layer did anyway :)
+			 */
+			tty = port->tty;
+
+			tty->ldisc.receive_buf(
+				tty,
+				data+1,
+				NULL,
+				urb->actual_length-1);
+
+			/*
+			 * No break here.
+			 * We want to resubmit the urb so we can read
+			 * again.
+			 */
+
+		case -EPROTO: /* taking inspiration from pl2303.c */
+
+			/* Continue trying to always read */
+			usb_fill_bulk_urb (
+				port->read_urb,
+				serial->dev, 
+				usb_rcvbulkpipe(serial->dev,
+					port->bulk_in_endpointAddress),
+				port->read_urb->transfer_buffer,
+				port->read_urb->transfer_buffer_length,
+				ir_read_bulk_callback,
+				port);
+
+			port->read_urb->transfer_flags = USB_QUEUE_BULK;
+
+			result = usb_submit_urb(port->read_urb);
+
+			if (result)
+				err("%s - failed resubmitting read urb, error %d",
+					__FUNCTION__, 
+					result);
+
+			break ;
+
+		default:
+			dbg("%s - nonzero read bulk status received: %d",
+				__FUNCTION__, 
+				urb->status);
+			break ;
+
+	}
 
-	/* Bypass flip-buffers, and feed the ldisc directly due to our 
-	 * potentally large buffer size.  Since we used to set low_latency,
-	 * this is exactly what the tty layer did anyway :) */
-	tty = port->tty;
-	tty->ldisc.receive_buf(tty, data+1, NULL, urb->actual_length-1);
-
-	/* Continue trying to always read  */
-	FILL_BULK_URB(port->read_urb, serial->dev, 
-		      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
-		      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
-		      ir_read_bulk_callback, port);
-	result = usb_submit_urb(port->read_urb);
-	if (result)
-		err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
 	return;
 }
 
@@ -390,12 +517,11 @@
 	unsigned char *transfer_buffer;
 	unsigned int cflag;
 	int result;
-	u8 baud;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	if ((!port->tty) || (!port->tty->termios)) {
-		dbg(__FUNCTION__" - no tty structures");
+		dbg("%s - no tty structures", __FUNCTION__);
 		return;
 	}
 
@@ -404,44 +530,70 @@
 	if (old_termios) {
 		if ((cflag == old_termios->c_cflag) &&
 		    (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
-			dbg(__FUNCTION__ " - nothing to change...");
+			dbg("%s - nothing to change...", __FUNCTION__);
 			return;
 		}
 	}
 
 	/* All we can change is the baud rate */
 	if (cflag & CBAUD) {
-		dbg (__FUNCTION__ " - asking for baud %d", tty_get_baud_rate(port->tty));
+
+		dbg ("%s - asking for baud %d",
+			__FUNCTION__,
+			tty_get_baud_rate(port->tty));
+
 		/* 
 		 * FIXME, we should compare the baud request against the
 		 * capability stated in the IR header that we got in the
 		 * startup funtion.
 		 */
 		switch (cflag & CBAUD) {
-			case B2400:	baud = SPEED_2400;	break;
-			case B9600:	baud = SPEED_9600;	break;
-			case B19200:	baud = SPEED_19200;	break;
-			case B38400:	baud = SPEED_38400;	break;
-			case B57600:	baud = SPEED_57600;	break;
-			case B115200:	baud = SPEED_115200;	break;
-			case B576000:	baud = SPEED_576000;	break;
-			case B1152000:	baud = SPEED_1152000;	break;
-			case B4000000:	baud = SPEED_4000000;	break;
+			case B2400:    ir_baud = SPEED_2400;    break;
 			default:
-				err ("ir-usb driver does not support the baudrate (%d) requested", tty_get_baud_rate(port->tty));
-				return;
+			case B9600:    ir_baud = SPEED_9600;    break;
+			case B19200:   ir_baud = SPEED_19200;   break;
+			case B38400:   ir_baud = SPEED_38400;   break;
+			case B57600:   ir_baud = SPEED_57600;   break;
+			case B115200:  ir_baud = SPEED_115200;  break;
+			case B576000:  ir_baud = SPEED_576000;  break;
+			case B1152000: ir_baud = SPEED_1152000; break;
+			case B4000000: ir_baud = SPEED_4000000; break;
 		}
-		
+
+		if (xbof == -1) {
+			ir_xbof = ir_xbof_change(ir_add_bof);
+		} else {
+			ir_xbof = ir_xbof_change(xbof) ;
+		}
+
+		/* Notify the tty driver that the termios have changed. */
+		port->tty->ldisc.set_termios(port->tty, NULL);
+
 		/* FIXME need to check to see if our write urb is busy right
-		 * now, or use a urb pool. */
-		/* send the baud change out on an "empty" data packet */
+		 * now, or use a urb pool.
+		 *
+		 * send the baud change out on an "empty" data packet
+		 */
 		transfer_buffer = port->write_urb->transfer_buffer;
-		transfer_buffer[0] = baud;
-		port->write_urb->transfer_buffer_length = 1;
-		port->write_urb->dev = port->serial->dev;
+		*transfer_buffer = ir_xbof | ir_baud;
+
+		usb_fill_bulk_urb (
+			port->write_urb,
+			port->serial->dev,
+			usb_sndbulkpipe(port->serial->dev,
+				port->bulk_out_endpointAddress),
+			port->write_urb->transfer_buffer,
+			1,
+			ir_write_bulk_callback,
+			port);
+
+		port->write_urb->transfer_flags
+			= USB_QUEUE_BULK
+			| USB_ZERO_PACKET;
+
 		result = usb_submit_urb (port->write_urb);
 		if (result)
-			err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+			err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
 	}
 	return;
 }
@@ -470,6 +622,8 @@
 
 MODULE_PARM(debug, "i");
 MODULE_PARM_DESC(debug, "Debug enabled or not");
+MODULE_PARM(xbof, "i");
+MODULE_PARM_DESC(xbof, "Force specific number of XBOFs");
 MODULE_PARM(buffer_size, "i");
 MODULE_PARM_DESC(buffer_size, "Size of the transfer buffers");
 
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/serial/keyspan.c linux/drivers/usb/serial/keyspan.c
--- v2.5.2/linux/drivers/usb/serial/keyspan.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/serial/keyspan.c	Thu Jan 17 14:06:53 2002
@@ -178,15 +178,7 @@
 /* Functions used by new usb-serial code. */
 static int __init keyspan_init (void)
 {
-	usb_serial_register (&keyspan_usa18x_pre_device);
-	usb_serial_register (&keyspan_usa19_pre_device);
-	usb_serial_register (&keyspan_usa19w_pre_device);
-	usb_serial_register (&keyspan_usa28_pre_device);
-	usb_serial_register (&keyspan_usa28x_pre_device);
-	usb_serial_register (&keyspan_usa28xa_pre_device);
-	usb_serial_register (&keyspan_usa28xb_pre_device);
-	usb_serial_register (&keyspan_usa49w_pre_device);
-
+	usb_serial_register (&keyspan_pre_device);
 	usb_serial_register (&keyspan_usa18x_device);
 	usb_serial_register (&keyspan_usa19_device);
 	usb_serial_register (&keyspan_usa19w_device);
@@ -203,15 +195,7 @@
 
 static void __exit keyspan_exit (void)
 {
-	usb_serial_deregister (&keyspan_usa18x_pre_device);
-	usb_serial_deregister (&keyspan_usa19_pre_device);
-	usb_serial_deregister (&keyspan_usa19w_pre_device);
-	usb_serial_deregister (&keyspan_usa28_pre_device);
-	usb_serial_deregister (&keyspan_usa28x_pre_device);
-	usb_serial_deregister (&keyspan_usa28xa_pre_device);
-	usb_serial_deregister (&keyspan_usa28xb_pre_device);
-	usb_serial_deregister (&keyspan_usa49w_pre_device);
-
+	usb_serial_deregister (&keyspan_pre_device);
 	usb_serial_deregister (&keyspan_usa18x_device);
 	usb_serial_deregister (&keyspan_usa19_device);
 	usb_serial_deregister (&keyspan_usa19w_device);
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/serial/keyspan.h linux/drivers/usb/serial/keyspan.h
--- v2.5.2/linux/drivers/usb/serial/keyspan.h	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/serial/keyspan.h	Thu Jan 17 14:06:53 2002
@@ -372,42 +372,15 @@
    ID pattern.  But, for now, it looks like we need slightly different
    behavior for each match. */
 
-static __devinitdata struct usb_device_id keyspan_usa18x_pre_ids[] = {
+/* usb_device_id table for the pre-firmware download keyspan devices */
+static __devinitdata struct usb_device_id keyspan_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) },
-	{ }	/* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa19_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_pre_product_id) },
-	{ } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa19w_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_pre_product_id) },
-	{ } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa28_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_pre_product_id) },
-	{ } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa28x_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_pre_product_id) },
-	{ } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa28xa_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_pre_product_id) },
-	{ } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa28xb_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_pre_product_id) },
-	{ } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa49w_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_pre_product_id) },
 	{ } /* Terminating entry */
 };
@@ -448,10 +421,10 @@
 };
 
     /* Structs for the devices, pre and post renumeration. */
-static struct usb_serial_device_type keyspan_usa18x_pre_device = {
+static struct usb_serial_device_type keyspan_pre_device = {
 	owner:			THIS_MODULE,
-	name:			"Keyspan USA18X - (without firmware)",
-	id_table:		keyspan_usa18x_pre_ids,
+	name:			"Keyspan - (without firmware)",
+	id_table:		keyspan_pre_ids,
 	num_interrupt_in:	NUM_DONT_CARE,
 	num_bulk_in:		NUM_DONT_CARE,
 	num_bulk_out:		NUM_DONT_CARE,
@@ -459,84 +432,6 @@
 	startup:		keyspan_fake_startup	
 };
 
-static struct usb_serial_device_type keyspan_usa19_pre_device = {
-	owner:			THIS_MODULE,
-	name:			"Keyspan USA19 - (without firmware)",
-	id_table:		keyspan_usa19_pre_ids,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		1,
-	startup:		keyspan_fake_startup	
-};
-
-
-static struct usb_serial_device_type keyspan_usa19w_pre_device = {
-	owner:			THIS_MODULE,
-	name:			"Keyspan USA19W - (without firmware)",
-	id_table:		keyspan_usa19w_pre_ids,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		1,
-	startup:		keyspan_fake_startup	
-};
-
-
-static struct usb_serial_device_type keyspan_usa28_pre_device = {
-	owner:			THIS_MODULE,
-	name:			"Keyspan USA28 - (without firmware)",
-	id_table:		keyspan_usa28_pre_ids,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		2,
-	startup:		keyspan_fake_startup	
-};
-
-static struct usb_serial_device_type keyspan_usa28x_pre_device = {
-	owner:			THIS_MODULE,
-	name:			"Keyspan USA28X - (without firmware)",
-	id_table:		keyspan_usa28x_pre_ids,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		2,
-	startup:		keyspan_fake_startup	
-};
-
-static struct usb_serial_device_type keyspan_usa28xa_pre_device = {
-	owner:			THIS_MODULE,
-	name:			"Keyspan USA28XA - (without firmware)",
-	id_table:		keyspan_usa28xa_pre_ids,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		2,
-	startup:		keyspan_fake_startup	
-};
-
-static struct usb_serial_device_type keyspan_usa28xb_pre_device = {
-	owner:			THIS_MODULE,
-	name:			"Keyspan USA28XB - (without firmware)",
-	id_table:		keyspan_usa28xb_pre_ids,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		2,
-	startup:		keyspan_fake_startup	
-};
-
-static struct usb_serial_device_type keyspan_usa49w_pre_device = {
-	owner:			THIS_MODULE,
-	name:			"Keyspan USA49W - (without firmware)",
-	id_table:		keyspan_usa49w_pre_ids,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		4,
-	startup:		keyspan_fake_startup	
-};
 
 static struct usb_serial_device_type keyspan_usa18x_device = {
 	owner:			THIS_MODULE,
@@ -550,8 +445,6 @@
 	close:			keyspan_close,
 	write:			keyspan_write,
 	write_room:		keyspan_write_room,
-	//write_bulk_callback: 	Not used - we define our own herbs
-	//read_int_callback:	keyspan_usa26_read_int_callback,
 	chars_in_buffer:	keyspan_chars_in_buffer,
 	throttle:		keyspan_rx_throttle,
 	unthrottle:		keyspan_rx_unthrottle,
@@ -574,8 +467,6 @@
 	close:			keyspan_close,
 	write:			keyspan_write,
 	write_room:		keyspan_write_room,
-//	write_bulk_callback: 	keyspan_write_bulk_callback,
-//	read_int_callback:	keyspan_usa28_read_int_callback,
 	chars_in_buffer:	keyspan_chars_in_buffer,
 	throttle:		keyspan_rx_throttle,
 	unthrottle:		keyspan_rx_unthrottle,
@@ -599,8 +490,6 @@
 	close:			keyspan_close,
 	write:			keyspan_write,
 	write_room:		keyspan_write_room,
-	//write_bulk_callback: 	Not used - we define our own herbs
-	//read_int_callback:	keyspan_usa26_read_int_callback,
 	chars_in_buffer:	keyspan_chars_in_buffer,
 	throttle:		keyspan_rx_throttle,
 	unthrottle:		keyspan_rx_unthrottle,
@@ -640,8 +529,6 @@
 	close:			keyspan_close,
 	write:			keyspan_write,
 	write_room:		keyspan_write_room,
-//	write_bulk_callback: 	keyspan_write_bulk_callback,
-//	read_int_callback:	keyspan_usa26_read_int_callback,
 	chars_in_buffer:	keyspan_chars_in_buffer,
 	throttle:		keyspan_rx_throttle,
 	unthrottle:		keyspan_rx_unthrottle,
@@ -665,8 +552,6 @@
 	close:			keyspan_close,
 	write:			keyspan_write,
 	write_room:		keyspan_write_room,
-//	write_bulk_callback: 	keyspan_write_bulk_callback,
-//	read_int_callback:	keyspan_usa26_read_int_callback,
 	chars_in_buffer:	keyspan_chars_in_buffer,
 	throttle:		keyspan_rx_throttle,
 	unthrottle:		keyspan_rx_unthrottle,
@@ -690,8 +575,6 @@
 	close:			keyspan_close,
 	write:			keyspan_write,
 	write_room:		keyspan_write_room,
-	//write_bulk_callback: 	Not used - we define our own herbs
-	//read_int_callback:	keyspan_usa26_read_int_callback,
 	chars_in_buffer:	keyspan_chars_in_buffer,
 	throttle:		keyspan_rx_throttle,
 	unthrottle:		keyspan_rx_unthrottle,
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/storage/protocol.c linux/drivers/usb/storage/protocol.c
--- v2.5.2/linux/drivers/usb/storage/protocol.c	Sun Jul 29 21:11:50 2001
+++ linux/drivers/usb/storage/protocol.c	Thu Jan 17 14:06:53 2002
@@ -1,6 +1,6 @@
 /* Driver for USB Mass Storage compliant devices
  *
- * $Id: protocol.c,v 1.10 2001/07/30 00:27:59 mdharm Exp $
+ * $Id: protocol.c,v 1.11 2002/01/13 06:40:25 mdharm Exp $
  *
  * Current development and maintenance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -76,7 +76,7 @@
 		data_ptr = (unsigned char *)srb->request_buffer;
 
 	/* Change the SCSI revision number */
-	data_ptr[2] |= 0x2;
+	data_ptr[2] = (data_ptr[2] & ~7) | 2;
 }
 
 /***********************************************************************
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/storage/unusual_devs.h linux/drivers/usb/storage/unusual_devs.h
--- v2.5.2/linux/drivers/usb/storage/unusual_devs.h	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/storage/unusual_devs.h	Sat Jan 19 14:33:35 2002
@@ -1,7 +1,7 @@
 /* Driver for USB Mass Storage compliant devices
  * Ununsual Devices File
  *
- * $Id: unusual_devs.h,v 1.24 2001/12/29 03:12:45 mdharm Exp $
+ * $Id: unusual_devs.h,v 1.25 2002/01/13 06:39:17 mdharm Exp $
  *
  * Current development and maintenance by:
  *   (c) 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -458,6 +458,14 @@
                 US_SC_ISD200, US_PR_BULK, isd200_Initialization,
                 0 ),
 #endif
+
+/* Submitted by Brian Hall <brihall@bigfoot.com>
+ * Needed for START_STOP flag */
+UNUSUAL_DEV(  0x0c76, 0x0003, 0x0100, 0x0100,
+		"JMTek",
+		"USBDrive",
+		US_SC_SCSI, US_PR_BULK, NULL,
+		US_FL_START_STOP ),
 
 /* Reported by Dan Pilone <pilone@slac.com>
  * The device needs the flags only.
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/storage/usb.c linux/drivers/usb/storage/usb.c
--- v2.5.2/linux/drivers/usb/storage/usb.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/storage/usb.c	Thu Jan 17 14:06:53 2002
@@ -1,6 +1,6 @@
 /* Driver for USB Mass Storage compliant devices
  *
- * $Id: usb.c,v 1.69 2001/11/11 03:33:03 mdharm Exp $
+ * $Id: usb.c,v 1.70 2002/01/06 07:14:12 mdharm Exp $
  *
  * Current development and maintenance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -314,10 +314,14 @@
 	 * This thread doesn't need any user-level access,
 	 * so get rid of all our resources..
 	 */
-	exit_files(current);
-	current->files = init_task.files;
-	atomic_inc(&current->files->count);
 	daemonize();
+
+	/* avoid getting signals */
+	spin_lock_irq(&current->sigmask_lock);
+	flush_signals(current);
+	sigfillset(&current->blocked);
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
 
 	/* set our name for identification purposes */
 	sprintf(current->comm, "usb-storage-%d", us->host_number);
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/stv680.c linux/drivers/usb/stv680.c
--- v2.5.2/linux/drivers/usb/stv680.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/stv680.c	Thu Jan 17 14:06:53 2002
@@ -43,6 +43,13 @@
  * 			   Took out sharpen function, ran code through
  * 			   Lindent, and did other minor tweaks to get
  * 			   things to work properly with 2.5.1
+ *
+ * ver 0.24 Jan, 2002 (kjs) 
+ *                         Fixed the problem with webcam crashing after
+ *                         two pictures. Changed the way pic is halved to 
+ *                         improve quality. Got rid of green line around 
+ *                         frame. Fix brightness reset when changing size 
+ *                         bug. Adjusted gamma filters slightly.
  */
 
 #include <linux/config.h>
@@ -65,7 +72,8 @@
 #include "stv680.h"
 
 static int video_nr = -1;
-static int swapRGB = 0;
+static int swapRGB = 0;   /* default for auto sleect */
+static int swapRGB_on = 0; /* default to allow auto select; -1=swap never, +1= swap always */
 
 static unsigned int debug = 0;
 
@@ -79,7 +87,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.23"
+#define DRIVER_VERSION "v0.24"
 #define DRIVER_AUTHOR "Kevin Sisson <kjsisson@bellsouth.net>"
 #define DRIVER_DESC "STV0680 USB Camera Driver"
 
@@ -88,8 +96,8 @@
 MODULE_LICENSE ("GPL");
 MODULE_PARM (debug, "i");
 MODULE_PARM_DESC (debug, "Debug enabled or not");
-MODULE_PARM (swapRGB, "i");
-MODULE_PARM_DESC (swapRGB, "Swap red and blue, e.g., for xawtv");
+MODULE_PARM (swapRGB_on, "i");
+MODULE_PARM_DESC (swapRGB_on, "Red/blue swap: 1=always, 0=auto, -1=never");
 MODULE_PARM (video_nr, "i");
 EXPORT_NO_SYMBOLS;
 
@@ -521,8 +529,15 @@
 	stv680->palette = STV_VIDEO_PALETTE;
 	stv680->depth = 24;	/* rgb24 bits */
 	swapRGB = 0;
-	PDEBUG (1, "STV(i): swapRGB is OFF");
-
+	if ((swapRGB_on == 0) && (swapRGB == 0))
+		PDEBUG (1, "STV(i): swapRGB is (auto) OFF");
+	else if ((swapRGB_on == 1) && (swapRGB == 1))
+		PDEBUG (1, "STV(i): swapRGB is (auto) ON");
+	else if (swapRGB_on == 1)
+		PDEBUG (1, "STV(i): swapRGB is (forced) ON");
+	else if (swapRGB_on == -1)
+		PDEBUG (1, "STV(i): swapRGB is (forced) OFF");
+	
 	if (stv_set_video_mode (stv680) < 0) {
 		PDEBUG (0, "STV(e): Could not set video mode in stv_init");
 		return -1;
@@ -543,6 +558,7 @@
 extern struct proc_dir_entry *video_proc_entry;
 
 #define YES_NO(x) ((x) ? "yes" : "no")
+#define ON_OFF(x) ((x) ? "(auto) on" : "(auto) off")
 
 static int stv680_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data)
 {
@@ -559,7 +575,13 @@
 	out += sprintf (out, "num_frames      : %d\n", STV680_NUMFRAMES);
 
 	out += sprintf (out, "Current size    : %ix%i\n", stv680->vwidth, stv680->vheight);
-	out += sprintf (out, "swapRGB         : %s\n", YES_NO (swapRGB));
+	if (swapRGB_on == 0)
+		out += sprintf (out, "swapRGB         : %s\n", ON_OFF (swapRGB));
+	else if (swapRGB_on == 1)
+		out += sprintf (out, "swapRGB         : (forced) on\n");
+	else if (swapRGB_on == -1)
+		out += sprintf (out, "swapRGB         : (forced) off\n");
+
 	out += sprintf (out, "Palette         : %i", stv680->palette);
 
 	out += sprintf (out, "\n");
@@ -671,9 +693,7 @@
 	if (stv680->brightness != p->brightness) {
 		stv680->chgbright = 1;
 		stv680->brightness = p->brightness;
-	} else {
-		stv680->chgbright = 0;
-	}
+	} 
 
 	stv680->whiteness = p->whiteness;	/* greyscale */
 	stv680->colour = p->colour;
@@ -888,7 +908,7 @@
 {
 	int x, y, i;
 	int w = stv680->cwidth;
-	int vw = stv680->cwidth, vh = stv680->cheight, vstep = 1;
+	int vw = stv680->cwidth, vh = stv680->cheight;
 	unsigned int p = 0;
 	int colour = 0, bayer = 0;
 	unsigned char *raw = buffer->data;
@@ -908,46 +928,23 @@
 		return;
 	}
 
-	if ((stv680->vwidth == 322) || (stv680->vwidth == 320)) {
+	if ((stv680->vwidth == 320) || (stv680->vwidth == 160)) {
 		vw = 320;
 		vh = 240;
-		vstep = 1;
 	}
-	if ((stv680->vwidth == 352)) {
+	if ((stv680->vwidth == 352) || (stv680->vwidth == 176)) {
 		vw = 352;
 		vh = 288;
-		vstep = 1;
 	}
-	if ((stv680->vwidth == 160)) {
-		vw = 160;
-		vh = 120;
-		vstep = 2;
-	}
-	if ((stv680->vwidth == 176)) {
-		vw = 176;
-		vh = 144;
-		vstep = 2;
-	}
-	memset (output, 0, 3 * vw * vh);	/* clear output matrix. Maybe not necessary. */
+
+	memset (output, 0, 3 * vw * vh);	/* clear output matrix. */
 
 	for (y = 0; y < vh; y++) {
 		for (x = 0; x < vw; x++) {
-
-			switch (vstep) {
-			case 1:
-				if (x & 1)
-					p = *(raw + y * w + (x >> 1));
-				else
-					p = *(raw + y * w + (x >> 1) + (w >> 1));
-				break;
-
-			case 2:
-				if (x & 1)
-					p = *(raw + ((y * w) << 1) + x);
-				else
-					p = *(raw + ((y * w) << 1) + x + (w >> 1));
-				break;
-			}
+			if (x & 1)
+				p = *(raw + y * w + (x >> 1));
+			else
+				p = *(raw + y * w + (x >> 1) + (w >> 1));
 
 			if (y & 1)
 				bayer = 2;
@@ -968,9 +965,10 @@
 				colour = 2;
 				break;
 			}
-			i = (y * vw + x) * 3;	/* output already zeroed out with memset */
+			i = (y * vw + x) * 3;	
 			*(output + i + colour) = (unsigned char) p;
 		}		/* for x */
+
 	}			/* for y */
 
 	/****** gamma correction plus hardcoded white balance */
@@ -979,6 +977,7 @@
 	   (pow(i/256.0, GAMMA)*255.0)*white balanceRGB where GAMMA=0.55, 1<i<255. 
 	   White balance (RGB)= 1.0, 1.17, 1.48. Values are calculated as double float and 
 	   converted to unsigned char. Values are in stv680.h  */
+
 	for (y = 0; y < vh; y++) {
 		for (x = 0; x < vw; x++) {
 			i = (y * vw + x) * 3;
@@ -1022,8 +1021,47 @@
 		}		/* for x */
 	}			/* for y  - end demosaic  */
 
+	/* fix top and bottom row, left and right side */
+	i = vw * 3;
+	memcpy (output, (output + i), i);
+	memcpy ((output + (vh * i)), (output + ((vh - 1) * i)), i);
+	for (y = 0; y < vh; y++) {
+		i = y * vw * 3;
+		memcpy ((output + i), (output + i + 3), 3);
+		memcpy ((output + i + (vw * 3)), (output + i + (vw - 1) * 3), 3);
+	}
+
+	/*  process all raw data, then trim to size if necessary */
+	if ((stv680->vwidth == 160) || (stv680->vwidth == 176))  {
+		i = 0;
+		for (y = 0; y < vh; y++) {
+			if (!(y & 1)) {
+				for (x = 0; x < vw; x++) {
+					p = (y * vw + x) * 3;
+					if (!(x & 1)) {
+						*(output + i) = *(output + p);
+						*(output + i + 1) = *(output + p + 1);
+						*(output + i + 2) = *(output + p + 2);
+						i += 3;
+					}
+				}  /* for x */
+			}
+		}  /* for y */
+	}
+	/* reset to proper width */
+	if ((stv680->vwidth == 160)) {
+		vw = 160;
+		vh = 120;
+	}
+	if ((stv680->vwidth == 176)) {
+		vw = 176;
+		vh = 144;
+	}
+
 	/* output is RGB; some programs want BGR  */
-	if (swapRGB == 1) {
+	/* swapRGB_on=0 -> program decides;  swapRGB_on=1, always swap */
+	/* swapRGB_on=-1, never swap */
+	if (((swapRGB == 1) && (swapRGB_on != -1)) || (swapRGB_on == 1)) {
 		for (y = 0; y < vh; y++) {
 			for (x = 0; x < vw; x++) {
 				i = (y * vw + x) * 3;
@@ -1242,7 +1280,7 @@
 				return -EFAULT;
 			}
 			copy_from_user (&p, arg, sizeof (p));
-			PDEBUG (2, "STV(i): palette set to RGB in VIDIOSPICT");
+			PDEBUG (2, "STV(i): palette set to %i in VIDIOSPICT", p.palette);
 
 			if (stv680_set_pict (stv680, &p))
 				return -EINVAL;
@@ -1309,8 +1347,8 @@
 			if (vm.format != STV_VIDEO_PALETTE) {
 				PDEBUG (2, "STV(i): VIDIOCMCAPTURE vm.format (%i) != VIDEO_PALETTE (%i)",
 					vm.format, STV_VIDEO_PALETTE);
-				if (vm.format == 3) {
-					PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is ON");
+				if ((vm.format == 3) && (swapRGB_on == 0))  {
+					PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is (auto) ON");
 					/* this may fix those apps (e.g., xawtv) that want BGR */
 					swapRGB = 1;
 				}
@@ -1320,8 +1358,10 @@
 				PDEBUG (2, "STV(e): VIDIOCMCAPTURE vm.frame > NUMFRAMES");
 				return -EINVAL;
 			}
-			if (stv680->frame[vm.frame].grabstate != FRAME_UNUSED) {
-				PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate != FRAME_UNUSED");
+			if ((stv680->frame[vm.frame].grabstate == FRAME_ERROR)
+			    || (stv680->frame[vm.frame].grabstate == FRAME_GRABBING)) {
+				PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate (%i) error",
+					stv680->frame[vm.frame].grabstate);
 				return -EBUSY;
 			}
 			/* Is this according to the v4l spec??? */
@@ -1390,7 +1430,7 @@
 	return 0;
 }
 
-static int stv680_mmap (struct video_device *dev, const char *adr, unsigned long size)
+static int stv680_mmap (struct vm_area_struct *vma, struct video_device *dev, const char *adr, unsigned long size)
 {
 	struct usb_stv *stv680 = (struct usb_stv *) dev;
 	unsigned long start = (unsigned long) adr;
@@ -1410,7 +1450,7 @@
 	pos = (unsigned long) stv680->fbuf;
 	while (size > 0) {
 		page = kvirt_to_pa (pos);
-		if (remap_page_range (start, page, PAGE_SIZE, PAGE_SHARED)) {
+		if (remap_page_range (vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
 			up (&stv680->lock);
 			return -EAGAIN;
 		}
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/stv680.h linux/drivers/usb/stv680.h
--- v2.5.2/linux/drivers/usb/stv680.h	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/stv680.h	Thu Jan 17 14:06:53 2002
@@ -43,7 +43,7 @@
 #define USB_PENCAM_PRODUCT_ID	0x0202
 #define PENCAM_TIMEOUT          1000
 /* fmt 4 */
-#define STV_VIDEO_PALETTE    VIDEO_PALETTE_RGB24
+#define STV_VIDEO_PALETTE       VIDEO_PALETTE_RGB24
 
 static __devinitdata struct usb_device_id device_table[] = {
 	{USB_DEVICE (USB_PENCAM_VENDOR_ID, USB_PENCAM_PRODUCT_ID)},
@@ -146,77 +146,78 @@
 	int nullpackets;
 };
 
-unsigned char red[256] = {
-	0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
-	21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47,
-	50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77,
-	79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97,
-	98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113,
-	114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126,
-	127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
-	139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149,
-	150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159,
-	160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168,
-	169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177,
-	177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185,
-	186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193,
-	193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200,
-	201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207,
-	208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214,
-	214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220,
-	221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227,
-	227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233,
-	233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239,
-	239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244,
-	245, 245, 246, 246
-};
+
+unsigned char red[256] = { 
+	0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 
+	18, 18, 18, 18, 18, 18, 18, 25, 30, 35, 38, 42, 
+	44, 47, 50, 53, 54, 57, 59, 61, 63, 65, 67, 69, 
+	71, 71, 73, 75, 77, 78, 80, 81, 82, 84, 85, 87, 
+	88, 89, 90, 91, 93, 94, 95, 97, 98, 98, 99, 101, 
+	102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 
+	114, 115, 116, 116, 117, 118, 119, 120, 121, 122, 123, 124, 
+	125, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134, 
+	134, 135, 135, 136, 137, 138, 139, 140, 140, 141, 142, 143, 
+	143, 143, 144, 145, 146, 147, 147, 148, 149, 150, 150, 151, 
+	152, 152, 152, 153, 154, 154, 155, 156, 157, 157, 158, 159, 
+	159, 160, 161, 161, 161, 162, 163, 163, 164, 165, 165, 166, 
+	167, 167, 168, 168, 169, 170, 170, 170, 171, 171, 172, 173, 
+	173, 174, 174, 175, 176, 176, 177, 178, 178, 179, 179, 179, 
+	180, 180, 181, 181, 182, 183, 183, 184, 184, 185, 185, 186, 
+	187, 187, 188, 188, 188, 188, 189, 190, 190, 191, 191, 192, 
+	192, 193, 193, 194, 195, 195, 196, 196, 197, 197, 197, 197, 
+	198, 198, 199, 199, 200, 201, 201, 202, 202, 203, 203, 204, 
+	204, 205, 205, 206, 206, 206, 206, 207, 207, 208, 208, 209, 
+	209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215, 
+	215, 215, 215, 216, 216, 217, 217, 218, 218, 218, 219, 219, 
+	220, 220, 221, 221 
+}; 
 
 unsigned char green[256] = {
-	0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
-	24, 24, 24, 24, 24, 24, 24, 32, 39, 45, 50, 54,
-	58, 62, 65, 69, 71, 74, 77, 79, 83, 85, 87, 90,
-	92, 93, 95, 98, 100, 101, 104, 106, 107, 109, 111, 113,
-	114, 116, 118, 119, 121, 122, 124, 126, 127, 128, 129, 132,
-	133, 134, 135, 136, 138, 140, 141, 142, 143, 145, 146, 147,
-	148, 149, 150, 152, 153, 154, 155, 156, 157, 159, 160, 161,
-	162, 163, 164, 166, 167, 168, 168, 169, 170, 171, 173, 174,
-	175, 176, 176, 177, 179, 180, 181, 182, 182, 183, 184, 186,
-	187, 187, 188, 189, 190, 191, 191, 193, 194, 195, 195, 196,
-	197, 198, 198, 200, 201, 201, 202, 203, 204, 204, 205, 207,
-	207, 208, 209, 209, 210, 211, 212, 212, 214, 215, 215, 216,
-	217, 217, 218, 218, 219, 221, 221, 222, 223, 223, 224, 225,
-	225, 226, 226, 228, 229, 229, 230, 231, 231, 232, 232, 233,
-	235, 235, 236, 236, 237, 238, 238, 239, 239, 241, 241, 242,
-	243, 243, 244, 244, 245, 245, 246, 248, 248, 249, 249, 250,
-	250, 251, 251, 252, 253, 253, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255
-};
+	0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 
+	21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47, 
+	50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77, 
+	79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97, 
+	98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113, 
+	114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126, 
+	127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 
+	139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, 
+	150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159, 
+	160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168, 
+	169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177, 
+	177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185, 
+	186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193, 
+	193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200, 
+	201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207, 
+	208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, 
+	214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220, 
+	221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 
+	227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 
+	233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, 
+	239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244, 
+	245, 245, 246, 246 
+}; 
 
 unsigned char blue[256] = {
-	0, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
-	31, 31, 31, 31, 31, 31, 31, 41, 50, 57, 63, 69,
-	74, 78, 82, 87, 90, 94, 97, 100, 105, 108, 111, 113,
-	116, 118, 121, 124, 127, 128, 131, 134, 136, 139, 140, 143,
-	145, 148, 149, 150, 153, 155, 156, 159, 161, 162, 164, 167,
-	168, 170, 171, 173, 174, 177, 179, 180, 182, 183, 185, 186,
-	187, 189, 190, 192, 193, 195, 196, 198, 199, 201, 202, 204,
-	205, 207, 208, 210, 211, 213, 213, 214, 216, 217, 219, 220,
-	222, 223, 223, 224, 226, 227, 229, 230, 230, 232, 233, 235,
-	236, 236, 238, 239, 241, 242, 242, 244, 245, 247, 247, 248,
-	250, 251, 251, 253, 254, 254, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255
-};
+	0, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 
+	23, 23, 23, 23, 23, 23, 23, 30, 37, 42, 47, 51, 
+	55, 58, 61, 64, 67, 70, 72, 74, 78, 80, 82, 84, 
+	86, 88, 90, 92, 94, 95, 97, 100, 101, 103, 104, 106, 
+	107, 110, 111, 112, 114, 115, 116, 118, 119, 121, 122, 124, 
+	125, 126, 127, 128, 129, 132, 133, 134, 135, 136, 137, 138, 
+	139, 140, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151, 
+	152, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162, 163, 
+	165, 166, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174, 
+	176, 176, 177, 178, 179, 180, 180, 181, 182, 183, 183, 184, 
+	185, 187, 187, 188, 189, 189, 190, 191, 192, 192, 193, 194, 
+	194, 195, 196, 196, 198, 199, 200, 200, 201, 202, 202, 203, 
+	204, 204, 205, 205, 206, 207, 207, 209, 210, 210, 211, 212, 
+	212, 213, 213, 214, 215, 215, 216, 217, 217, 218, 218, 220, 
+	221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 
+	228, 228, 229, 229, 231, 231, 232, 233, 233, 234, 234, 235, 
+	235, 236, 236, 237, 238, 238, 239, 239, 240, 240, 242, 242, 
+	243, 243, 244, 244, 245, 246, 246, 247, 247, 248, 248, 249, 
+	249, 250, 250, 251, 251, 253, 253, 254, 254, 255, 255, 255, 
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
+	255, 255, 255, 255 
+}; 
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
--- v2.5.2/linux/drivers/usb/usb.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/usb.c	Thu Jan 17 14:06:53 2002
@@ -2252,6 +2252,14 @@
 		return -EINVAL;
 	}
 
+	/* 9.4.10 says devices don't need this, if the interface
+	   only has one alternate setting */
+	if (iface->num_altsetting == 1) {
+		warn("ignoring set_interface for dev %d, iface %d, alt %d",
+			dev->devnum, interface, alternate);
+		return 0;
+	}
+
 	if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
 	    USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE, alternate,
 	    interface, NULL, 0, HZ * 5)) < 0)
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/usbvideo.c linux/drivers/usb/usbvideo.c
--- v2.5.2/linux/drivers/usb/usbvideo.c	Wed Oct 10 23:42:46 2001
+++ linux/drivers/usb/usbvideo.c	Tue Jan 15 10:56:35 2002
@@ -1184,7 +1184,7 @@
 	return -EINVAL;
 }
 
-int usbvideo_v4l_mmap(struct video_device *dev, const char *adr, unsigned long size)
+int usbvideo_v4l_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr, unsigned long size)
 {
 	uvd_t *uvd = (uvd_t *) dev;
 	unsigned long start = (unsigned long) adr;
@@ -1199,7 +1199,7 @@
 	pos = (unsigned long) uvd->fbuf;
 	while (size > 0) {
 		page = usbvideo_kvirt_to_pa(pos);
-		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
+		if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
 			return -EAGAIN;
 
 		start += PAGE_SIZE;
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/usbvideo.h linux/drivers/usb/usbvideo.h
--- v2.5.2/linux/drivers/usb/usbvideo.h	Wed Oct 10 23:42:46 2001
+++ linux/drivers/usb/usbvideo.h	Tue Jan 15 10:56:35 2002
@@ -349,7 +349,7 @@
 void usbvideo_v4l_close(struct video_device *dev);
 int usbvideo_v4l_initialize(struct video_device *dev);
 int usbvideo_v4l_ioctl(struct video_device *dev, unsigned int cmd, void *arg);
-int usbvideo_v4l_mmap(struct video_device *dev, const char *adr, unsigned long size);
+int usbvideo_v4l_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr, unsigned long size);
 int usbvideo_v4l_open(struct video_device *dev, int flags);
 long usbvideo_v4l_read(struct video_device *dev, char *buf,
 			unsigned long count, int noblock);
diff -u --recursive --new-file v2.5.2/linux/drivers/usb/vicam.c linux/drivers/usb/vicam.c
--- v2.5.2/linux/drivers/usb/vicam.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/usb/vicam.c	Tue Jan 15 10:56:35 2002
@@ -670,7 +670,7 @@
         return ret;
 }
 
-static int vicam_v4l_mmap(struct video_device *dev, const char *adr, unsigned long size)
+static int vicam_v4l_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr, unsigned long size)
 {
 	struct usb_vicam *vicam = (struct usb_vicam *)dev;
 	unsigned long start = (unsigned long)adr;
@@ -691,7 +691,7 @@
 	pos = (unsigned long)vicam->fbuf;
 	while (size > 0) {
 		page = kvirt_to_pa(pos);
-		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
+		if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
 			up(&vicam->sem);
 			return -EAGAIN;
 		}
diff -u --recursive --new-file v2.5.2/linux/drivers/video/acornfb.c linux/drivers/video/acornfb.c
--- v2.5.2/linux/drivers/video/acornfb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/acornfb.c	Tue Jan 15 10:56:35 2002
@@ -1152,7 +1152,7 @@
 	 * some updates to the screen occasionally, but process switches
 	 * should cause the caches and buffers to be flushed often enough.
 	 */
-	if (io_remap_page_range(vma->vm_start, off,
+	if (io_remap_page_range(vma, vma->vm_start, off,
 				vma->vm_end - vma->vm_start,
 				vma->vm_page_prot))
 		return -EAGAIN;
diff -u --recursive --new-file v2.5.2/linux/drivers/video/aty/atyfb_base.c linux/drivers/video/aty/atyfb_base.c
--- v2.5.2/linux/drivers/video/aty/atyfb_base.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/video/aty/atyfb_base.c	Tue Jan 15 10:56:35 2002
@@ -343,7 +343,7 @@
     { 0x4751, 0x4751, 0x00, 0x00, m64n_gtc_ppl, 230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT },
 
     /* 3D RAGE XL */
-    { 0x4752, 0x4752, 0x00, 0x00, m64n_xl, 230, 120, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT | M64F_XL_DLL },
+    { 0x4752, 0x4752, 0x00, 0x00, m64n_xl, 230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT | M64F_XL_DLL },
 
     /* Mach64 LT PRO */
     { 0x4c42, 0x4c42, 0x00, 0x00, m64n_ltp_a,   230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP },
@@ -1394,7 +1394,7 @@
 		pgprot_val(vma->vm_page_prot) &= ~(fb->mmap_map[i].prot_mask);
 		pgprot_val(vma->vm_page_prot) |= fb->mmap_map[i].prot_flag;
 
-		if (remap_page_range(vma->vm_start + page, map_offset,
+		if (remap_page_range(vma, vma->vm_start + page, map_offset,
 				     map_size, vma->vm_page_prot))
 			return -EAGAIN;
 
@@ -1986,7 +1986,7 @@
     disp = &info->disp;
 
     strcpy(info->fb_info.modename, atyfb_name);
-    info->fb_info.node = -1;
+    info->fb_info.node = NODEV;
     info->fb_info.fbops = &atyfb_ops;
     info->fb_info.disp = disp;
     strcpy(info->fb_info.fontname, fontname);
diff -u --recursive --new-file v2.5.2/linux/drivers/video/controlfb.c linux/drivers/video/controlfb.c
--- v2.5.2/linux/drivers/video/controlfb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/controlfb.c	Tue Jan 15 10:56:35 2002
@@ -444,7 +444,7 @@
        		return -EINVAL;
        off += start;
        vma->vm_pgoff = off >> PAGE_SHIFT;
-       if (io_remap_page_range(vma->vm_start, off,
+       if (io_remap_page_range(vma, vma->vm_start, off,
            vma->vm_end - vma->vm_start, vma->vm_page_prot))
                return -EAGAIN;
 
diff -u --recursive --new-file v2.5.2/linux/drivers/video/fbmem.c linux/drivers/video/fbmem.c
--- v2.5.2/linux/drivers/video/fbmem.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/video/fbmem.c	Tue Jan 15 10:56:35 2002
@@ -581,7 +581,7 @@
 	vma->vm_flags |= VM_IO;
 #if defined(__sparc_v9__)
 	vma->vm_flags |= (VM_SHM | VM_LOCKED);
-	if (io_remap_page_range(vma->vm_start, off,
+	if (io_remap_page_range(vma, vma->vm_start, off,
 				vma->vm_end - vma->vm_start, vma->vm_page_prot, 0))
 		return -EAGAIN;
 #else
@@ -614,7 +614,7 @@
 #else
 #warning What do we have to do here??
 #endif
-	if (io_remap_page_range(vma->vm_start, off,
+	if (io_remap_page_range(vma, vma->vm_start, off,
 			     vma->vm_end - vma->vm_start, vma->vm_page_prot))
 		return -EAGAIN;
 #endif /* !__sparc_v9__ */
diff -u --recursive --new-file v2.5.2/linux/drivers/video/igafb.c linux/drivers/video/igafb.c
--- v2.5.2/linux/drivers/video/igafb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/igafb.c	Tue Jan 15 10:56:35 2002
@@ -283,7 +283,7 @@
 		pgprot_val(vma->vm_page_prot) &= ~(fb->mmap_map[i].prot_mask);
 		pgprot_val(vma->vm_page_prot) |= fb->mmap_map[i].prot_flag;
 
-		if (remap_page_range(vma->vm_start + page, map_offset,
+		if (remap_page_range(vma, vma->vm_start + page, map_offset,
 				     map_size, vma->vm_page_prot))
 			return -EAGAIN;
 
diff -u --recursive --new-file v2.5.2/linux/drivers/video/matrox/matroxfb_base.h linux/drivers/video/matrox/matroxfb_base.h
--- v2.5.2/linux/drivers/video/matrox/matroxfb_base.h	Fri Nov  9 14:07:41 2001
+++ linux/drivers/video/matrox/matroxfb_base.h	Tue Jan 15 10:56:35 2002
@@ -124,10 +124,6 @@
 #endif
 #endif
 
-#ifdef __sparc__
-#error "Sorry, I have no idea how to do this on sparc... There is mapioaddr... With bus_type parameter..."
-#endif
-
 #if defined(__m68k__)
 #define MAP_BUSTOVIRT
 #else
diff -u --recursive --new-file v2.5.2/linux/drivers/video/sbusfb.c linux/drivers/video/sbusfb.c
--- v2.5.2/linux/drivers/video/sbusfb.c	Mon Jan 14 18:25:10 2002
+++ linux/drivers/video/sbusfb.c	Tue Jan 15 10:56:35 2002
@@ -214,7 +214,7 @@
 		}
 		if (page + map_size > size)
 			map_size = size - page;
-		r = io_remap_page_range (vma->vm_start+page, map_offset, map_size, vma->vm_page_prot, fb->iospace);
+		r = io_remap_page_range(vma, vma->vm_start+page, map_offset, map_size, vma->vm_page_prot, fb->iospace);
 		if (r)
 			return -EAGAIN;
 		page += map_size;
diff -u --recursive --new-file v2.5.2/linux/drivers/video/sgivwfb.c linux/drivers/video/sgivwfb.c
--- v2.5.2/linux/drivers/video/sgivwfb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/sgivwfb.c	Tue Jan 15 10:56:35 2002
@@ -847,7 +847,7 @@
   offset += sgivwfb_mem_phys;
   pgprot_val(vma->vm_page_prot) = pgprot_val(vma->vm_page_prot) | _PAGE_PCD;
   vma->vm_flags |= VM_IO;
-  if (remap_page_range(vma->vm_start, offset, size, vma->vm_page_prot))
+  if (remap_page_range(vma, vma->vm_start, offset, size, vma->vm_page_prot))
     return -EAGAIN;
   vma->vm_file = file;
   printk(KERN_DEBUG "sgivwfb: mmap framebuffer P(%lx)->V(%lx)\n", offset, vma->vm_start);
diff -u --recursive --new-file v2.5.2/linux/drivers/video/sis/sis_main.c linux/drivers/video/sis/sis_main.c
--- v2.5.2/linux/drivers/video/sis/sis_main.c	Fri Nov  9 14:11:14 2001
+++ linux/drivers/video/sis/sis_main.c	Tue Jan 15 10:56:35 2002
@@ -2175,7 +2175,7 @@
 	if (boot_cpu_data.x86 > 3)
 		pgprot_val (vma->vm_page_prot) |= _PAGE_PCD;
 #endif
-	if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start, vma->vm_page_prot)) 
+	if (io_remap_page_range(vma, vma->vm_start, off, vma->vm_end - vma->vm_start, vma->vm_page_prot)) 
 		return -EAGAIN;
 	return 0;
 
diff -u --recursive --new-file v2.5.2/linux/fs/Makefile.lib linux/fs/Makefile.lib
--- v2.5.2/linux/fs/Makefile.lib	Mon Jan 14 18:25:10 2002
+++ linux/fs/Makefile.lib	Tue Jan 15 14:15:53 2002
@@ -1,2 +1,2 @@
-obj-$(CONFIG_FS_JFFS2)		+= crc32.o
+obj-$(CONFIG_JFFS2_FS)		+= crc32.o
 obj-$(CONFIG_EFI_PARTITION)	+= crc32.o
diff -u --recursive --new-file v2.5.2/linux/fs/binfmt_misc.c linux/fs/binfmt_misc.c
--- v2.5.2/linux/fs/binfmt_misc.c	Sat Oct 20 19:14:42 2001
+++ linux/fs/binfmt_misc.c	Thu Jan 17 14:25:43 2002
@@ -49,6 +49,8 @@
 } Node;
 
 static rwlock_t entries_lock __attribute__((unused)) = RW_LOCK_UNLOCKED;
+static struct vfsmount *bm_mnt;
+static int entry_count = 0;
 
 /* 
  * Check if we support the binfmt
@@ -390,10 +392,15 @@
 	Node *e = inode->u.generic_ip;
 
 	if (e) {
+		struct vfsmount *mnt;
 		write_lock(&entries_lock);
 		list_del(&e->list);
+		mnt = bm_mnt;
+		if (!--entry_count)
+			bm_mnt = NULL;
 		write_unlock(&entries_lock);
 		kfree(e);
+		mntput(mnt);
 	}
 }
 
@@ -404,8 +411,7 @@
 	write_lock(&entries_lock);
 	dentry = e->dentry;
 	if (dentry) {
-		list_del(&e->list);
-		INIT_LIST_HEAD(&e->list);
+		list_del_init(&e->list);
 		e->dentry = NULL;
 	}
 	write_unlock(&entries_lock);
@@ -484,12 +490,16 @@
 	write:		bm_entry_write,
 };
 
+static struct file_system_type bm_fs_type;
+
 /* /register */
 
 static ssize_t bm_register_write(struct file *file, const char *buffer,
 			       size_t count, loff_t *ppos)
 {
 	Node *e;
+	struct inode *inode;
+	struct vfsmount *mnt = NULL;
 	struct dentry *root, *dentry;
 	struct super_block *sb = file->f_vfsmnt->mnt_sb;
 	int err = 0;
@@ -503,31 +513,52 @@
 	down(&root->d_inode->i_sem);
 	dentry = lookup_one_len(e->name, root, strlen(e->name));
 	err = PTR_ERR(dentry);
-	if (!IS_ERR(dentry)) {
-		down(&root->d_inode->i_zombie);
-		if (dentry->d_inode) {
-			err = -EEXIST;
-		} else {
-			struct inode * inode = bm_get_inode(sb, S_IFREG | 0644);
-			err = -ENOMEM;
+	if (IS_ERR(dentry))
+		goto out;
 
-			if (inode) {
-				write_lock(&entries_lock);
+	down(&root->d_inode->i_zombie);
 
-				e->dentry = dget(dentry);
-				inode->u.generic_ip = e;
-				inode->i_fop = &bm_entry_operations;
-				d_instantiate(dentry, inode);
+	err = -EEXIST;
+	if (dentry->d_inode)
+		goto out2;
 
-				list_add(&e->list, &entries);
-				write_unlock(&entries_lock);
+	inode = bm_get_inode(sb, S_IFREG | 0644);
 
-				err = 0;
-			}
+	err = -ENOMEM;
+	if (!inode)
+		goto out2;
+
+	write_lock(&entries_lock);
+	if (!bm_mnt) {
+		write_unlock(&entries_lock);
+		mnt = kern_mount(&bm_fs_type);
+		if (IS_ERR(mnt)) {
+			err = PTR_ERR(mnt);
+			iput(inode);
+			inode = NULL;
+			goto out2;
 		}
-		up(&root->d_inode->i_zombie);
-		dput(dentry);
+		write_lock(&entries_lock);
+		if (!bm_mnt)
+			bm_mnt = mnt;
 	}
+	mntget(bm_mnt);
+	entry_count++;
+
+	e->dentry = dget(dentry);
+	inode->u.generic_ip = e;
+	inode->i_fop = &bm_entry_operations;
+	d_instantiate(dentry, inode);
+
+	list_add(&e->list, &entries);
+	write_unlock(&entries_lock);
+
+	mntput(mnt);
+	err = 0;
+out2:
+	up(&root->d_inode->i_zombie);
+	dput(dentry);
+out:
 	up(&root->d_inode->i_sem);
 	dput(root);
 
@@ -687,23 +718,13 @@
 
 static DECLARE_FSTYPE(bm_fs_type, "binfmt_misc", bm_read_super, FS_SINGLE|FS_LITTER);
 
-static struct vfsmount *bm_mnt;
-
 static int __init init_misc_binfmt(void)
 {
 	int err = register_filesystem(&bm_fs_type);
 	if (!err) {
-		bm_mnt = kern_mount(&bm_fs_type);
-		err = PTR_ERR(bm_mnt);
-		if (IS_ERR(bm_mnt))
+		err = register_binfmt(&misc_format);
+		if (err)
 			unregister_filesystem(&bm_fs_type);
-		else {
-			err = register_binfmt(&misc_format);
-			if (err) {
-				unregister_filesystem(&bm_fs_type);
-				kern_umount(bm_mnt);
-			}
-		}
 	}
 	return err;
 }
@@ -712,7 +733,6 @@
 {
 	unregister_binfmt(&misc_format);
 	unregister_filesystem(&bm_fs_type);
-	kern_umount(bm_mnt);
 }
 
 EXPORT_NO_SYMBOLS;
diff -u --recursive --new-file v2.5.2/linux/fs/block_dev.c linux/fs/block_dev.c
--- v2.5.2/linux/fs/block_dev.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/block_dev.c	Fri Jan 18 16:00:26 2002
@@ -220,17 +220,19 @@
 static struct super_block *bd_read_super(struct super_block *sb, void *data, int silent)
 {
 	static struct super_operations sops = {};
-	struct inode *root = new_inode(sb);
-	if (!root)
-		return NULL;
-	root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
-	root->i_uid = root->i_gid = 0;
-	root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
+	struct inode *root;
+
 	sb->s_maxbytes = ~0ULL;
 	sb->s_blocksize = 1024;
 	sb->s_blocksize_bits = 10;
 	sb->s_magic = 0x62646576;
 	sb->s_op = &sops;
+	root = new_inode(sb);
+	if (!root)
+		return NULL;
+	root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
+	root->i_uid = root->i_gid = 0;
+	root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
 	sb->s_root = d_alloc(NULL, &(const struct qstr) { "bdev:", 5, 0 });
 	if (!sb->s_root) {
 		iput(root);
diff -u --recursive --new-file v2.5.2/linux/fs/buffer.c linux/fs/buffer.c
--- v2.5.2/linux/fs/buffer.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/buffer.c	Thu Jan 17 14:29:59 2002
@@ -582,23 +582,13 @@
 	return bh;
 }
 
-void buffer_insert_inode_queue(struct buffer_head *bh, struct inode *inode)
+void buffer_insert_list(struct buffer_head *bh, struct list_head *list)
 {
 	spin_lock(&lru_list_lock);
 	if (bh->b_inode)
 		list_del(&bh->b_inode_buffers);
-	bh->b_inode = inode;
-	list_add(&bh->b_inode_buffers, &inode->i_dirty_buffers);
-	spin_unlock(&lru_list_lock);
-}
-
-void buffer_insert_inode_data_queue(struct buffer_head *bh, struct inode *inode)
-{
-	spin_lock(&lru_list_lock);
-	if (bh->b_inode)
-		list_del(&bh->b_inode_buffers);
-	bh->b_inode = inode;
-	list_add(&bh->b_inode_buffers, &inode->i_dirty_data_buffers);
+	bh->b_inode = 1;
+	list_add(&bh->b_inode_buffers, list);
 	spin_unlock(&lru_list_lock);
 }
 
@@ -606,7 +596,7 @@
    remove_inode_queue functions.  */
 static void __remove_inode_queue(struct buffer_head *bh)
 {
-	bh->b_inode = NULL;
+	bh->b_inode = 0;
 	list_del(&bh->b_inode_buffers);
 }
 
@@ -826,73 +816,24 @@
  * any newly dirty buffers for write.
  */
 
-int fsync_inode_buffers(struct inode *inode)
-{
-	struct buffer_head *bh;
-	struct inode tmp;
-	int err = 0, err2;
-	
-	INIT_LIST_HEAD(&tmp.i_dirty_buffers);
-	
-	spin_lock(&lru_list_lock);
-
-	while (!list_empty(&inode->i_dirty_buffers)) {
-		bh = BH_ENTRY(inode->i_dirty_buffers.next);
-		list_del(&bh->b_inode_buffers);
-		if (!buffer_dirty(bh) && !buffer_locked(bh))
-			bh->b_inode = NULL;
-		else {
-			bh->b_inode = &tmp;
-			list_add(&bh->b_inode_buffers, &tmp.i_dirty_buffers);
-			if (buffer_dirty(bh)) {
-				get_bh(bh);
-				spin_unlock(&lru_list_lock);
-				ll_rw_block(WRITE, 1, &bh);
-				brelse(bh);
-				spin_lock(&lru_list_lock);
-			}
-		}
-	}
-
-	while (!list_empty(&tmp.i_dirty_buffers)) {
-		bh = BH_ENTRY(tmp.i_dirty_buffers.prev);
-		remove_inode_queue(bh);
-		get_bh(bh);
-		spin_unlock(&lru_list_lock);
-		wait_on_buffer(bh);
-		if (!buffer_uptodate(bh))
-			err = -EIO;
-		brelse(bh);
-		spin_lock(&lru_list_lock);
-	}
-	
-	spin_unlock(&lru_list_lock);
-	err2 = osync_inode_buffers(inode);
-
-	if (err)
-		return err;
-	else
-		return err2;
-}
-
-int fsync_inode_data_buffers(struct inode *inode)
+int fsync_buffers_list(struct list_head *list)
 {
 	struct buffer_head *bh;
-	struct inode tmp;
+	struct list_head tmp;
 	int err = 0, err2;
 	
-	INIT_LIST_HEAD(&tmp.i_dirty_data_buffers);
+	INIT_LIST_HEAD(&tmp);
 	
 	spin_lock(&lru_list_lock);
 
-	while (!list_empty(&inode->i_dirty_data_buffers)) {
-		bh = BH_ENTRY(inode->i_dirty_data_buffers.next);
+	while (!list_empty(list)) {
+		bh = BH_ENTRY(list->next);
 		list_del(&bh->b_inode_buffers);
 		if (!buffer_dirty(bh) && !buffer_locked(bh))
-			bh->b_inode = NULL;
+			bh->b_inode = 0;
 		else {
-			bh->b_inode = &tmp;
-			list_add(&bh->b_inode_buffers, &tmp.i_dirty_data_buffers);
+			bh->b_inode = 1;
+			list_add(&bh->b_inode_buffers, &tmp);
 			if (buffer_dirty(bh)) {
 				get_bh(bh);
 				spin_unlock(&lru_list_lock);
@@ -903,8 +844,8 @@
 		}
 	}
 
-	while (!list_empty(&tmp.i_dirty_data_buffers)) {
-		bh = BH_ENTRY(tmp.i_dirty_data_buffers.prev);
+	while (!list_empty(&tmp)) {
+		bh = BH_ENTRY(tmp.prev);
 		remove_inode_queue(bh);
 		get_bh(bh);
 		spin_unlock(&lru_list_lock);
@@ -916,7 +857,7 @@
 	}
 	
 	spin_unlock(&lru_list_lock);
-	err2 = osync_inode_data_buffers(inode);
+	err2 = osync_buffers_list(list);
 
 	if (err)
 		return err;
@@ -935,19 +876,19 @@
  * write will not be flushed to disk by the osync.
  */
 
-int osync_inode_buffers(struct inode *inode)
+int osync_buffers_list(struct list_head *list)
 {
 	struct buffer_head *bh;
-	struct list_head *list;
+	struct list_head *p;
 	int err = 0;
 
 	spin_lock(&lru_list_lock);
 	
  repeat:
 	
-	for (list = inode->i_dirty_buffers.prev; 
-	     bh = BH_ENTRY(list), list != &inode->i_dirty_buffers;
-	     list = bh->b_inode_buffers.prev) {
+	for (p = list->prev; 
+	     bh = BH_ENTRY(p), p != list;
+	     p = bh->b_inode_buffers.prev) {
 		if (buffer_locked(bh)) {
 			get_bh(bh);
 			spin_unlock(&lru_list_lock);
@@ -963,36 +904,6 @@
 	spin_unlock(&lru_list_lock);
 	return err;
 }
-
-int osync_inode_data_buffers(struct inode *inode)
-{
-	struct buffer_head *bh;
-	struct list_head *list;
-	int err = 0;
-
-	spin_lock(&lru_list_lock);
-	
- repeat:
-
-	for (list = inode->i_dirty_data_buffers.prev; 
-	     bh = BH_ENTRY(list), list != &inode->i_dirty_data_buffers;
-	     list = bh->b_inode_buffers.prev) {
-		if (buffer_locked(bh)) {
-			get_bh(bh);
-			spin_unlock(&lru_list_lock);
-			wait_on_buffer(bh);
-			if (!buffer_uptodate(bh))
-				err = -EIO;
-			brelse(bh);
-			spin_lock(&lru_list_lock);
-			goto repeat;
-		}
-	}
-
-	spin_unlock(&lru_list_lock);
-	return err;
-}
-
 
 /*
  * Invalidate any and all dirty buffers on a given inode.  We are
diff -u --recursive --new-file v2.5.2/linux/fs/devpts/inode.c linux/fs/devpts/inode.c
--- v2.5.2/linux/fs/devpts/inode.c	Thu Oct 25 00:02:26 2001
+++ linux/fs/devpts/inode.c	Fri Jan 18 16:00:26 2002
@@ -139,6 +139,11 @@
 		printk("devpts: called with bogus options\n");
 		goto fail_free;
 	}
+	s->u.generic_sbp = (void *) sbi;
+	s->s_blocksize = 1024;
+	s->s_blocksize_bits = 10;
+	s->s_magic = DEVPTS_SUPER_MAGIC;
+	s->s_op = &devpts_sops;
 
 	inode = new_inode(s);
 	if (!inode)
@@ -153,11 +158,6 @@
 	inode->i_fop = &devpts_root_operations;
 	inode->i_nlink = 2;
 
-	s->u.generic_sbp = (void *) sbi;
-	s->s_blocksize = 1024;
-	s->s_blocksize_bits = 10;
-	s->s_magic = DEVPTS_SUPER_MAGIC;
-	s->s_op = &devpts_sops;
 	s->s_root = d_alloc_root(inode);
 	if (s->s_root)
 		return s;
diff -u --recursive --new-file v2.5.2/linux/fs/ext2/balloc.c linux/fs/ext2/balloc.c
--- v2.5.2/linux/fs/ext2/balloc.c	Tue Dec 18 14:56:39 2001
+++ linux/fs/ext2/balloc.c	Thu Jan 17 14:24:50 2002
@@ -42,19 +42,20 @@
 	unsigned long group_desc;
 	unsigned long desc;
 	struct ext2_group_desc * gdp;
+	struct ext2_sb_info *sbi = &sb->u.ext2_sb;
 
-	if (block_group >= sb->u.ext2_sb.s_groups_count) {
+	if (block_group >= sbi->s_groups_count) {
 		ext2_error (sb, "ext2_get_group_desc",
 			    "block_group >= groups_count - "
 			    "block_group = %d, groups_count = %lu",
-			    block_group, sb->u.ext2_sb.s_groups_count);
+			    block_group, sbi->s_groups_count);
 
 		return NULL;
 	}
 	
 	group_desc = block_group / EXT2_DESC_PER_BLOCK(sb);
 	desc = block_group % EXT2_DESC_PER_BLOCK(sb);
-	if (!sb->u.ext2_sb.s_group_desc[group_desc]) {
+	if (!sbi->s_group_desc[group_desc]) {
 		ext2_error (sb, "ext2_get_group_desc",
 			    "Group descriptor not loaded - "
 			    "block_group = %d, group_desc = %lu, desc = %lu",
@@ -62,10 +63,9 @@
 		return NULL;
 	}
 	
-	gdp = (struct ext2_group_desc *) 
-	      sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
+	gdp = (struct ext2_group_desc *) sbi->s_group_desc[group_desc]->b_data;
 	if (bh)
-		*bh = sb->u.ext2_sb.s_group_desc[group_desc];
+		*bh = sbi->s_group_desc[group_desc];
 	return gdp + desc;
 }
 
@@ -73,37 +73,26 @@
  * Read the bitmap for a given block_group, reading into the specified 
  * slot in the superblock's bitmap cache.
  *
- * Return >=0 on success or a -ve error code.
+ * Return buffer_head on success or NULL in case of failure.
  */
 
-static int read_block_bitmap (struct super_block * sb,
-			       unsigned int block_group,
-			       unsigned long bitmap_nr)
+static struct buffer_head *read_block_bitmap(struct super_block *sb,
+						unsigned int block_group)
 {
 	struct ext2_group_desc * gdp;
 	struct buffer_head * bh = NULL;
-	int retval = -EIO;
 	
 	gdp = ext2_get_group_desc (sb, block_group, NULL);
 	if (!gdp)
 		goto error_out;
-	retval = 0;
 	bh = sb_bread(sb, le32_to_cpu(gdp->bg_block_bitmap));
-	if (!bh) {
+	if (!bh)
 		ext2_error (sb, "read_block_bitmap",
 			    "Cannot read block bitmap - "
 			    "block_group = %d, block_bitmap = %lu",
 			    block_group, (unsigned long) gdp->bg_block_bitmap);
-		retval = -EIO;
-	}
-	/*
-	 * On IO error, just leave a zero in the superblock's block pointer for
-	 * this group.  The IO will be retried next time.
-	 */
 error_out:
-	sb->u.ext2_sb.s_block_bitmap_number[bitmap_nr] = block_group;
-	sb->u.ext2_sb.s_block_bitmap[bitmap_nr] = bh;
-	return retval;
+	return bh;
 }
 
 /*
@@ -117,134 +106,65 @@
  * 2/ If the file system contains less than EXT2_MAX_GROUP_LOADED groups,
  *    this function reads the bitmap without maintaining a LRU cache.
  * 
- * Return the slot used to store the bitmap, or a -ve error code.
+ * Return the buffer_head of the bitmap or ERR_PTR(-ve).
  */
-static int __load_block_bitmap (struct super_block * sb,
-			        unsigned int block_group)
+static struct buffer_head *load_block_bitmap(struct super_block * sb,
+						unsigned int block_group)
 {
-	int i, j, retval = 0;
-	unsigned long block_bitmap_number;
-	struct buffer_head * block_bitmap;
+	struct ext2_sb_info *sbi = &sb->u.ext2_sb;
+	int i, slot = 0;
+	struct buffer_head *bh = sbi->s_block_bitmap[0];
 
-	if (block_group >= sb->u.ext2_sb.s_groups_count)
+	if (block_group >= sbi->s_groups_count)
 		ext2_panic (sb, "load_block_bitmap",
 			    "block_group >= groups_count - "
 			    "block_group = %d, groups_count = %lu",
-			    block_group, sb->u.ext2_sb.s_groups_count);
-
-	if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED) {
-		if (sb->u.ext2_sb.s_block_bitmap[block_group]) {
-			if (sb->u.ext2_sb.s_block_bitmap_number[block_group] ==
-			    block_group)
-				return block_group;
-			ext2_error (sb, "__load_block_bitmap",
-				    "block_group != block_bitmap_number");
-		}
-		retval = read_block_bitmap (sb, block_group, block_group);
-		if (retval < 0)
-			return retval;
-		return block_group;
-	}
-
-	for (i = 0; i < sb->u.ext2_sb.s_loaded_block_bitmaps &&
-		    sb->u.ext2_sb.s_block_bitmap_number[i] != block_group; i++)
-		;
-	if (i < sb->u.ext2_sb.s_loaded_block_bitmaps &&
-  	    sb->u.ext2_sb.s_block_bitmap_number[i] == block_group) {
-		block_bitmap_number = sb->u.ext2_sb.s_block_bitmap_number[i];
-		block_bitmap = sb->u.ext2_sb.s_block_bitmap[i];
-		for (j = i; j > 0; j--) {
-			sb->u.ext2_sb.s_block_bitmap_number[j] =
-				sb->u.ext2_sb.s_block_bitmap_number[j - 1];
-			sb->u.ext2_sb.s_block_bitmap[j] =
-				sb->u.ext2_sb.s_block_bitmap[j - 1];
-		}
-		sb->u.ext2_sb.s_block_bitmap_number[0] = block_bitmap_number;
-		sb->u.ext2_sb.s_block_bitmap[0] = block_bitmap;
-
-		/*
-		 * There's still one special case here --- if block_bitmap == 0
-		 * then our last attempt to read the bitmap failed and we have
-		 * just ended up caching that failure.  Try again to read it.
-		 */
-		if (!block_bitmap)
-			retval = read_block_bitmap (sb, block_group, 0);
-	} else {
-		if (sb->u.ext2_sb.s_loaded_block_bitmaps < EXT2_MAX_GROUP_LOADED)
-			sb->u.ext2_sb.s_loaded_block_bitmaps++;
-		else
-			brelse (sb->u.ext2_sb.s_block_bitmap[EXT2_MAX_GROUP_LOADED - 1]);
-		for (j = sb->u.ext2_sb.s_loaded_block_bitmaps - 1; j > 0; j--) {
-			sb->u.ext2_sb.s_block_bitmap_number[j] =
-				sb->u.ext2_sb.s_block_bitmap_number[j - 1];
-			sb->u.ext2_sb.s_block_bitmap[j] =
-				sb->u.ext2_sb.s_block_bitmap[j - 1];
-		}
-		retval = read_block_bitmap (sb, block_group, 0);
-	}
-	return retval;
-}
-
-/*
- * Load the block bitmap for a given block group.  First of all do a couple
- * of fast lookups for common cases and then pass the request onto the guts
- * of the bitmap loader.
- *
- * Return the slot number of the group in the superblock bitmap cache's on
- * success, or a -ve error code.
- *
- * There is still one inconsistency here --- if the number of groups in this
- * filesystems is <= EXT2_MAX_GROUP_LOADED, then we have no way of 
- * differentiating between a group for which we have never performed a bitmap
- * IO request, and a group for which the last bitmap read request failed.
- */
-static inline int load_block_bitmap (struct super_block * sb,
-				     unsigned int block_group)
-{
-	int slot;
+			    block_group, sbi->s_groups_count);
 	
 	/*
 	 * Do the lookup for the slot.  First of all, check if we're asking
 	 * for the same slot as last time, and did we succeed that last time?
 	 */
-	if (sb->u.ext2_sb.s_loaded_block_bitmaps > 0 &&
-	    sb->u.ext2_sb.s_block_bitmap_number[0] == block_group &&
-	    sb->u.ext2_sb.s_block_bitmap[0]) {
-		return 0;
-	}
-	/*
-	 * Or can we do a fast lookup based on a loaded group on a filesystem
-	 * small enough to be mapped directly into the superblock?
-	 */
-	else if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED && 
-		 sb->u.ext2_sb.s_block_bitmap_number[block_group] == block_group &&
-		 sb->u.ext2_sb.s_block_bitmap[block_group]) {
+	if (sbi->s_loaded_block_bitmaps > 0 &&
+	    sbi->s_block_bitmap_number[0] == block_group && bh)
+		goto found;
+
+	if (sbi->s_groups_count <= EXT2_MAX_GROUP_LOADED) {
 		slot = block_group;
-	}
-	/*
-	 * If not, then do a full lookup for this block group.
-	 */
-	else {
-		slot = __load_block_bitmap (sb, block_group);
+		bh = sbi->s_block_bitmap[slot];
+		if (!bh)
+			goto read_it;
+		if (sbi->s_block_bitmap_number[slot] == slot)
+			goto found;
+		ext2_panic (sb, "__load_block_bitmap",
+			    "block_group != block_bitmap_number");
 	}
 
-	/*
-	 * <0 means we just got an error
-	 */
-	if (slot < 0)
-		return slot;
-	
-	/*
-	 * If it's a valid slot, we may still have cached a previous IO error,
-	 * in which case the bh in the superblock cache will be zero.
-	 */
-	if (!sb->u.ext2_sb.s_block_bitmap[slot])
-		return -EIO;
-	
-	/*
-	 * Must have been read in OK to get this far.
-	 */
-	return slot;
+	bh = NULL;
+	for (i = 0; i < sbi->s_loaded_block_bitmaps &&
+		    sbi->s_block_bitmap_number[i] != block_group; i++)
+		;
+	if (i < sbi->s_loaded_block_bitmaps)
+		bh = sbi->s_block_bitmap[i];
+	else if (sbi->s_loaded_block_bitmaps < EXT2_MAX_GROUP_LOADED)
+		sbi->s_loaded_block_bitmaps++;
+	else
+		brelse (sbi->s_block_bitmap[--i]);
+
+	while (i--) {
+		sbi->s_block_bitmap_number[i+1] = sbi->s_block_bitmap_number[i];
+		sbi->s_block_bitmap[i+1] = sbi->s_block_bitmap[i];
+	}
+
+read_it:
+	if (!bh)
+		bh = read_block_bitmap(sb, block_group);
+	sbi->s_block_bitmap_number[slot] = block_group;
+	sbi->s_block_bitmap[slot] = bh;
+	if (!bh)
+		return ERR_PTR(-EIO);
+found:
+	return bh;
 }
 
 /* Free given blocks, update quota and i_blocks field */
@@ -256,7 +176,6 @@
 	unsigned long block_group;
 	unsigned long bit;
 	unsigned long i;
-	int bitmap_nr;
 	unsigned long overflow;
 	struct super_block * sb;
 	struct ext2_group_desc * gdp;
@@ -293,11 +212,10 @@
 		overflow = bit + count - EXT2_BLOCKS_PER_GROUP(sb);
 		count -= overflow;
 	}
-	bitmap_nr = load_block_bitmap (sb, block_group);
-	if (bitmap_nr < 0)
+	bh = load_block_bitmap (sb, block_group);
+	if (IS_ERR(bh))
 		goto error_return;
 	
-	bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
 	gdp = ext2_get_group_desc (sb, block_group, &bh2);
 	if (!gdp)
 		goto error_return;
@@ -361,7 +279,6 @@
 	struct buffer_head * bh2;
 	char * p, * r;
 	int i, j, k, tmp;
-	int bitmap_nr;
 	struct super_block * sb;
 	struct ext2_group_desc * gdp;
 	struct ext2_super_block * es;
@@ -404,12 +321,10 @@
 		if (j)
 			goal_attempts++;
 #endif
-		bitmap_nr = load_block_bitmap (sb, i);
-		if (bitmap_nr < 0)
+		bh = load_block_bitmap (sb, i);
+		if (IS_ERR(bh))
 			goto io_error;
 		
-		bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
-
 		ext2_debug ("goal is at %d:%d.\n", i, j);
 
 		if (!ext2_test_bit(j, bh->b_data)) {
@@ -477,11 +392,10 @@
 	}
 	if (k >= sb->u.ext2_sb.s_groups_count)
 		goto out;
-	bitmap_nr = load_block_bitmap (sb, i);
-	if (bitmap_nr < 0)
+	bh = load_block_bitmap (sb, i);
+	if (IS_ERR(bh))
 		goto io_error;
 	
-	bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
 	r = memscan(bh->b_data, 0, EXT2_BLOCKS_PER_GROUP(sb) >> 3);
 	j = (r - bh->b_data) << 3;
 	if (j < EXT2_BLOCKS_PER_GROUP(sb))
@@ -619,7 +533,6 @@
 #ifdef EXT2FS_DEBUG
 	struct ext2_super_block * es;
 	unsigned long desc_count, bitmap_count, x;
-	int bitmap_nr;
 	struct ext2_group_desc * gdp;
 	int i;
 	
@@ -629,16 +542,16 @@
 	bitmap_count = 0;
 	gdp = NULL;
 	for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
+		struct buffer_head *bh;
 		gdp = ext2_get_group_desc (sb, i, NULL);
 		if (!gdp)
 			continue;
 		desc_count += le16_to_cpu(gdp->bg_free_blocks_count);
-		bitmap_nr = load_block_bitmap (sb, i);
-		if (bitmap_nr < 0)
+		bh = load_block_bitmap (sb, i);
+		if (IS_ERR(bh))
 			continue;
 		
-		x = ext2_count_free (sb->u.ext2_sb.s_block_bitmap[bitmap_nr],
-				     sb->s_blocksize);
+		x = ext2_count_free (bh, sb->s_blocksize);
 		printk ("group %d: stored = %d, counted = %lu\n",
 			i, le16_to_cpu(gdp->bg_free_blocks_count), x);
 		bitmap_count += x;
@@ -720,7 +633,6 @@
 	struct ext2_super_block * es;
 	unsigned long desc_count, bitmap_count, x, j;
 	unsigned long desc_blocks;
-	int bitmap_nr;
 	struct ext2_group_desc * gdp;
 	int i;
 
@@ -733,11 +645,9 @@
 		if (!gdp)
 			continue;
 		desc_count += le16_to_cpu(gdp->bg_free_blocks_count);
-		bitmap_nr = load_block_bitmap (sb, i);
-		if (bitmap_nr < 0)
+		bh = load_block_bitmap (sb, i);
+		if (IS_ERR(bh))
 			continue;
-
-		bh = EXT2_SB(sb)->s_block_bitmap[bitmap_nr];
 
 		if (ext2_bg_has_super(sb, i) && !ext2_test_bit(0, bh->b_data))
 			ext2_error(sb, __FUNCTION__,
diff -u --recursive --new-file v2.5.2/linux/fs/fat/dir.c linux/fs/fat/dir.c
--- v2.5.2/linux/fs/fat/dir.c	Fri Oct 12 13:48:42 2001
+++ linux/fs/fat/dir.c	Tue Jan 15 10:58:53 2002
@@ -538,7 +538,6 @@
 	if (!memcmp(de->name,MSDOS_DOT,11))
 		inum = inode->i_ino;
 	else if (!memcmp(de->name,MSDOS_DOTDOT,11)) {
-/*		inum = fat_parent_ino(inode,0); */
 		inum = filp->f_dentry->d_parent->d_inode->i_ino;
 	} else {
 		struct inode *tmp = fat_iget(sb, ino);
@@ -727,7 +726,13 @@
 	offset = curr = 0;
 	*bh = NULL;
 	row = 0;
-	while (fat_get_entry(dir,&curr,bh,de,ino) > -1) {
+	while (fat_get_entry(dir, &curr, bh, de, ino) > -1) {
+		/* check the maximum size of directory */
+		if (curr >= FAT_MAX_DIR_SIZE) {
+			fat_brelse(sb, *bh);
+			return -ENOSPC;
+		}
+
 		if (IS_FREE((*de)->name)) {
 			if (++row == slots)
 				return offset;
@@ -742,7 +747,10 @@
 	if (!new_bh)
 		return -ENOSPC;
 	fat_brelse(sb, new_bh);
-	do fat_get_entry(dir,&curr,bh,de,ino); while (++row<slots);
+	do {
+		fat_get_entry(dir, &curr, bh, de, ino);
+	} while (++row < slots);
+
 	return offset;
 }
 
diff -u --recursive --new-file v2.5.2/linux/fs/fat/inode.c linux/fs/fat/inode.c
--- v2.5.2/linux/fs/fat/inode.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/fat/inode.c	Wed Jan 16 10:20:23 2002
@@ -208,7 +208,7 @@
 }
 
 
-static int parse_options(char *options,int *fat, int *debug,
+static int parse_options(char *options, int *debug,
 			 struct fat_mount_options *opts,
 			 char *cvf_format, char *cvf_options)
 {
@@ -227,7 +227,7 @@
 	opts->shortname = 0;
 	opts->utf8 = 0;
 	opts->iocharset = NULL;
-	*debug = *fat = 0;
+	*debug = 0;
 
 	if (!options)
 		goto out;
@@ -305,13 +305,8 @@
 			else *debug = 1;
 		}
 		else if (!strcmp(this_char,"fat")) {
-			if (!value || !*value) ret = 0;
-			else {
-				*fat = simple_strtoul(value,&value,0);
-				if (*value || (*fat != 12 && *fat != 16 &&
-					       *fat != 32)) 
-					ret = 0;
-			}
+			printk("FAT: fat option is obsolete, "
+			       "not supported now\n");
 		}
 		else if (!strcmp(this_char,"quiet")) {
 			if (value) ret = 0;
@@ -328,8 +323,6 @@
 		else if (!strcmp(this_char,"codepage") && value) {
 			opts->codepage = simple_strtoul(value,&value,0);
 			if (*value) ret = 0;
-			else printk ("MSDOS FS: Using codepage %d\n",
-					opts->codepage);
 		}
 		else if (!strcmp(this_char,"iocharset") && value) {
 			p = value;
@@ -348,7 +341,6 @@
 					opts->iocharset = buffer;
 					memcpy(buffer, p, len);
 					buffer[len] = 0;
-					printk("MSDOS FS: IO charset %s\n", buffer);
 				} else
 					ret = 0;
 			}
@@ -373,11 +365,37 @@
 	return ret;
 }
 
+static void fat_calc_dir_size(struct inode *inode)
+{
+	struct super_block *sb = inode->i_sb;
+	int nr;
+
+	inode->i_size = 0;
+	if (MSDOS_I(inode)->i_start == 0)
+		return;
+
+	nr = MSDOS_I(inode)->i_start;
+	do {
+		inode->i_size += 1 << MSDOS_SB(sb)->cluster_bits;
+		if (!(nr = fat_access(sb, nr, -1))) {
+			printk("FAT: Directory %ld: bad FAT\n",
+			       inode->i_ino);
+			break;
+		}
+		if (inode->i_size > FAT_MAX_DIR_SIZE) {
+			fat_fs_panic(sb, "Directory %ld: "
+				     "exceeded the maximum size of directory",
+				     inode->i_ino);
+			inode->i_size = FAT_MAX_DIR_SIZE;
+			break;
+		}
+	} while (nr != -1);
+}
+
 static void fat_read_root(struct inode *inode)
 {
 	struct super_block *sb = inode->i_sb;
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
-	int nr;
 
 	INIT_LIST_HEAD(&MSDOS_I(inode)->i_fat_hash);
 	MSDOS_I(inode)->i_location = 0;
@@ -391,16 +409,7 @@
 	inode->i_fop = &fat_dir_operations;
 	if (sbi->fat_bits == 32) {
 		MSDOS_I(inode)->i_start = sbi->root_cluster;
-		if ((nr = MSDOS_I(inode)->i_start) != 0) {
-			while (nr != -1) {
-				inode->i_size += 1 << sbi->cluster_bits;
-				if (!(nr = fat_access(sb, nr, -1))) {
-					printk("Directory %ld: bad FAT\n",
-					       inode->i_ino);
-					break;
-				}
-			}
-		}
+		fat_calc_dir_size(inode);
 	} else {
 		MSDOS_I(inode)->i_start = 0;
 		inode->i_size = sbi->dir_entries * sizeof(struct msdos_dir_entry);
@@ -550,11 +559,9 @@
 	struct buffer_head *bh;
 	struct fat_boot_sector *b;
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
-	char *p;
-	int logical_sector_size, hard_blksize, fat_clusters = 0;
+	int logical_sector_size, fat_clusters, debug, cp;
 	unsigned int total_sectors, rootdir_sectors;
-	int fat32, debug, error, fat, cp;
-	struct fat_mount_options opts;
+	long error = -EIO;
 	char buf[50];
 	int i;
 	char cvf_format[21];
@@ -562,22 +569,20 @@
 
 	cvf_format[0] = '\0';
 	cvf_options[0] = '\0';
-	sbi->cvf_format = NULL;
 	sbi->private_data = NULL;
 
-	sbi->dir_ops = fs_dir_inode_ops;
-
-	sb->s_maxbytes = MAX_NON_LFS;
+	sb->s_magic = MSDOS_SUPER_MAGIC;
 	sb->s_op = &fat_sops;
+	sbi->dir_ops = fs_dir_inode_ops;
+	sbi->cvf_format = &default_cvf;
 
-	opts.isvfat = sbi->options.isvfat;
-	if (!parse_options((char *) data, &fat, &debug, &opts,
+	if (!parse_options((char *)data, &debug, &sbi->options,
 			   cvf_format, cvf_options))
 		goto out_fail;
-	/* N.B. we should parse directly into the sb structure */
-	memcpy(&(sbi->options), &opts, sizeof(struct fat_mount_options));
 
 	fat_cache_init();
+	/* set up enough so that it can read an inode */
+	init_MUTEX(&sbi->fat_lock);
 
 	sb_min_blocksize(sb, 512);
 	bh = sb_bread(sb, 0);
@@ -586,37 +591,37 @@
 		goto out_fail;
 	}
 
-/*
- * The DOS3 partition size limit is *not* 32M as many people think.  
- * Instead, it is 64K sectors (with the usual sector size being
- * 512 bytes, leading to a 32M limit).
- * 
- * DOS 3 partition managers got around this problem by faking a 
- * larger sector size, ie treating multiple physical sectors as 
- * a single logical sector.
- * 
- * We can accommodate this scheme by adjusting our cluster size,
- * fat_start, and data_start by an appropriate value.
- *
- * (by Drew Eckhardt)
- */
-
-
 	b = (struct fat_boot_sector *) bh->b_data;
+	if (!b->secs_track) {
+		if (!silent)
+			printk("FAT: bogus sectors-per-track value\n");
+		brelse(bh);
+		goto out_invalid;
+	}
+	if (!b->heads) {
+		if (!silent)
+			printk("FAT: bogus number-of-heads value\n");
+		brelse(bh);
+		goto out_invalid;
+	}
 	logical_sector_size =
 		CF_LE_W(get_unaligned((unsigned short *) &b->sector_size));
 	if (!logical_sector_size
-	    || (logical_sector_size & (logical_sector_size - 1))) {
-		printk("FAT: bogus logical sector size %d\n",
-		       logical_sector_size);
+	    || (logical_sector_size & (logical_sector_size - 1))
+	    || (logical_sector_size < 512)
+	    || (PAGE_CACHE_SIZE < logical_sector_size)) {
+		if (!silent)
+			printk("FAT: bogus logical sector size %d\n",
+			       logical_sector_size);
 		brelse(bh);
 		goto out_invalid;
 	}
-
 	sbi->cluster_size = b->cluster_size;
 	if (!sbi->cluster_size
 	    || (sbi->cluster_size & (sbi->cluster_size - 1))) {
-		printk("FAT: bogus cluster size %d\n", sbi->cluster_size);
+		if (!silent)
+			printk("FAT: bogus cluster size %d\n",
+			       sbi->cluster_size);
 		brelse(bh);
 		goto out_invalid;
 	}
@@ -625,47 +630,62 @@
 		printk("FAT: logical sector size too small for device"
 		       " (logical sector size = %d)\n", logical_sector_size);
 		brelse(bh);
-		goto out_invalid;
+		goto out_fail;
 	}
+	if (logical_sector_size > sb->s_blocksize) {
+		brelse(bh);
 
-	hard_blksize = sb->s_blocksize;
+		if (!sb_set_blocksize(sb, logical_sector_size)) {
+			printk("FAT: unable to set blocksize %d\n",
+			       logical_sector_size);
+			goto out_fail;
+		}
+		bh = sb_bread(sb, 0);
+		if (bh == NULL) {
+			printk("FAT: unable to read boot sector"
+			       " (logical sector size = %lu)\n",
+			       sb->s_blocksize);
+			goto out_fail;
+		}
+		b = (struct fat_boot_sector *) bh->b_data;
+	}
 
-	sbi->cluster_bits = ffs(logical_sector_size * sbi->cluster_size) - 1;
+	sbi->cluster_bits = ffs(sb->s_blocksize * sbi->cluster_size) - 1;
 	sbi->fats = b->fats;
+	sbi->fat_bits = 0;		/* Don't know yet */
 	sbi->fat_start = CF_LE_W(b->reserved);
-	if (!b->fat_length && b->fat32_length) {
+	sbi->fat_length = CF_LE_W(b->fat_length);
+	sbi->root_cluster = 0;
+	sbi->free_clusters = -1;	/* Don't know yet */
+	sbi->prev_free = 0;
+
+	if (!sbi->fat_length && b->fat32_length) {
 		struct fat_boot_fsinfo *fsinfo;
 		struct buffer_head *fsinfo_bh;
-		int fsinfo_block, fsinfo_offset;
 
 		/* Must be FAT32 */
-		fat32 = 1;
+		sbi->fat_bits = 32;
 		sbi->fat_length = CF_LE_L(b->fat32_length);
 		sbi->root_cluster = CF_LE_L(b->root_cluster);
 
-		sbi->fsinfo_sector = CF_LE_W(b->info_sector);
 		/* MC - if info_sector is 0, don't multiply by 0 */
+		sbi->fsinfo_sector = CF_LE_W(b->info_sector);
 		if (sbi->fsinfo_sector == 0)
 			sbi->fsinfo_sector = 1;
 
-		fsinfo_block =
-			(sbi->fsinfo_sector * logical_sector_size) / hard_blksize;
-		fsinfo_offset =
-			(sbi->fsinfo_sector * logical_sector_size) % hard_blksize;
-		fsinfo_bh = bh;
-		if (fsinfo_block != 0) {
-			fsinfo_bh = sb_bread(sb, fsinfo_block);
-			if (fsinfo_bh == NULL) {
-				printk("FAT: bread failed, FSINFO block"
-				       " (blocknr = %d)\n", fsinfo_block);
-				brelse(bh);
-				goto out_invalid;
-			}
+		fsinfo_bh = sb_bread(sb, sbi->fsinfo_sector);
+		if (fsinfo_bh == NULL) {
+			printk("FAT: bread failed, FSINFO block"
+			       " (sector = %lu)\n", sbi->fsinfo_sector);
+			brelse(bh);
+			goto out_fail;
 		}
-		fsinfo = (struct fat_boot_fsinfo *)&fsinfo_bh->b_data[fsinfo_offset];
+
+		fsinfo = (struct fat_boot_fsinfo *)fsinfo_bh->b_data;
 		if (!IS_FSINFO(fsinfo)) {
 			printk("FAT: Did not find valid FSINFO signature.\n"
-			       "Found signature1 0x%x signature2 0x%x sector=%ld.\n",
+			       "     Found signature1 0x%08x signature2 0x%08x"
+			       " (sector = %lu)\n",
 			       CF_LE_L(fsinfo->signature1),
 			       CF_LE_L(fsinfo->signature2),
 			       sbi->fsinfo_sector);
@@ -673,144 +693,113 @@
 			sbi->free_clusters = CF_LE_L(fsinfo->free_clusters);
 		}
 
-		if (fsinfo_block != 0)
-			brelse(fsinfo_bh);
-	} else {
-		fat32 = 0;
-		sbi->fat_length = CF_LE_W(b->fat_length);
-		sbi->root_cluster = 0;
-		sbi->free_clusters = -1; /* Don't know yet */
+		brelse(fsinfo_bh);
 	}
 
-	sbi->dir_per_block = logical_sector_size / sizeof(struct msdos_dir_entry);
+	sbi->dir_per_block = sb->s_blocksize / sizeof(struct msdos_dir_entry);
 	sbi->dir_per_block_bits = ffs(sbi->dir_per_block) - 1;
 
 	sbi->dir_start = sbi->fat_start + sbi->fats * sbi->fat_length;
 	sbi->dir_entries =
 		CF_LE_W(get_unaligned((unsigned short *)&b->dir_entries));
+	if (sbi->dir_entries & (sbi->dir_per_block - 1)) {
+		printk("FAT: bogus directroy-entries per block\n");
+		brelse(bh);
+		goto out_invalid;
+	}
+
 	rootdir_sectors = sbi->dir_entries
-		* sizeof(struct msdos_dir_entry) / logical_sector_size;
+		* sizeof(struct msdos_dir_entry) / sb->s_blocksize;
 	sbi->data_start = sbi->dir_start + rootdir_sectors;
 	total_sectors = CF_LE_W(get_unaligned((unsigned short *)&b->sectors));
 	if (total_sectors == 0)
 		total_sectors = CF_LE_L(b->total_sect);
 	sbi->clusters = (total_sectors - sbi->data_start) / sbi->cluster_size;
 
-	error = 0;
-	if (!error) {
-		sbi->fat_bits = fat32 ? 32 :
-			(fat ? fat :
-			 (sbi->clusters > MSDOS_FAT12 ? 16 : 12));
-		fat_clusters =
-			sbi->fat_length * logical_sector_size * 8 / sbi->fat_bits;
-		error = !sbi->fats || (sbi->dir_entries & (sbi->dir_per_block - 1))
-			|| sbi->clusters + 2 > fat_clusters + MSDOS_MAX_EXTRA
-			|| logical_sector_size < 512
-			|| PAGE_CACHE_SIZE < logical_sector_size
-			|| !b->secs_track || !b->heads;
-	}
-	brelse(bh);
+	if (sbi->fat_bits != 32)
+		sbi->fat_bits = (sbi->clusters > MSDOS_FAT12) ? 16 : 12;
 
-	if (error)
-		goto out_invalid;
+	/* check that FAT table does not overflow */
+	fat_clusters = sbi->fat_length * sb->s_blocksize * 8 / sbi->fat_bits;
+	if (sbi->clusters > fat_clusters - 2)
+		sbi->clusters = fat_clusters - 2;
+
+	brelse(bh);
 
-	sb_set_blocksize(sb, logical_sector_size);
-	sbi->cvf_format = &default_cvf;
 	if (!strcmp(cvf_format, "none"))
 		i = -1;
 	else
-		i = detect_cvf(sb,cvf_format);
-	if (i >= 0)
-		error = cvf_formats[i]->mount_cvf(sb, cvf_options);
-	if (error || debug) {
-		/* The MSDOS_CAN_BMAP is obsolete, but left just to remember */
-		printk("[MS-DOS FS Rel. 12,FAT %d,check=%c,conv=%c,"
-		       "uid=%d,gid=%d,umask=%03o%s]\n",
-		       sbi->fat_bits,opts.name_check,
-		       opts.conversion,opts.fs_uid,opts.fs_gid,opts.fs_umask,
-		       MSDOS_CAN_BMAP(sbi) ? ",bmap" : "");
-		printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%ld,ds=%ld,de=%d,data=%ld,"
-		       "se=%u,ts=%u,ls=%d,rc=%ld,fc=%u]\n",
-		       b->media, sbi->cluster_size, sbi->fats,
-		       sbi->fat_start, sbi->fat_length, sbi->dir_start,
-		       sbi->dir_entries, sbi->data_start,
-		       CF_LE_W(get_unaligned((unsigned short *)&b->sectors)),
-		       CF_LE_L(b->total_sect), logical_sector_size,
-		       sbi->root_cluster, sbi->free_clusters);
-		printk ("hard sector size = %d\n", hard_blksize);
-	}
-	if (i < 0)
-		if (sbi->clusters + 2 > fat_clusters)
-			sbi->clusters = fat_clusters - 2;
-	if (error)
-		goto out_invalid;
-
-	sb->s_magic = MSDOS_SUPER_MAGIC;
-	/* set up enough so that it can read an inode */
-	init_MUTEX(&sbi->fat_lock);
-	sbi->prev_free = 0;
+		i = detect_cvf(sb, cvf_format);
+	if (i >= 0) {
+		if (cvf_formats[i]->mount_cvf(sb, cvf_options))
+			goto out_invalid;
+	}
 
-	cp = opts.codepage ? opts.codepage : 437;
+	cp = sbi->options.codepage ? sbi->options.codepage : 437;
 	sprintf(buf, "cp%d", cp);
 	sbi->nls_disk = load_nls(buf);
 	if (! sbi->nls_disk) {
 		/* Fail only if explicit charset specified */
-		if (opts.codepage != 0)
+		if (sbi->options.codepage != 0) {
+			printk("FAT: codepage %s not found\n", buf);
 			goto out_fail;
+		}
 		sbi->options.codepage = 0; /* already 0?? */
 		sbi->nls_disk = load_nls_default();
 	}
+	if (!silent)
+		printk("FAT: Using codepage %s\n", sbi->nls_disk->charset);
 
-	sbi->nls_io = NULL;
-	if (sbi->options.isvfat && !opts.utf8) {
-		p = opts.iocharset ? opts.iocharset : CONFIG_NLS_DEFAULT;
-		sbi->nls_io = load_nls(p);
-		if (! sbi->nls_io)
-			/* Fail only if explicit charset specified */
-			if (opts.iocharset)
-				goto out_unload_nls;
+	if (sbi->options.isvfat && !sbi->options.utf8) {
+		if (sbi->options.iocharset != NULL) {
+			sbi->nls_io = load_nls(sbi->options.iocharset);
+			if (!sbi->nls_io) {
+				printk("FAT: IO charset %s not found\n",
+				       sbi->options.iocharset);
+				goto out_fail;
+			}
+		} else
+			sbi->nls_io = load_nls_default();
+		if (!silent)
+			printk("FAT: Using IO charset %s\n",
+			       sbi->nls_io->charset);
 	}
-	if (! sbi->nls_io)
-		sbi->nls_io = load_nls_default();
 
 	root_inode = new_inode(sb);
 	if (!root_inode)
-		goto out_unload_nls;
+		goto out_fail;
+
 	root_inode->i_ino = MSDOS_ROOT_INO;
 	root_inode->i_version = 0;
 	fat_read_root(root_inode);
 	insert_inode_hash(root_inode);
 	sb->s_root = d_alloc_root(root_inode);
-	if (!sb->s_root)
-		goto out_no_root;
+	if (!sb->s_root) {
+		printk("FAT: get root inode failed\n");
+		iput(root_inode);
+		goto out_fail;
+	}
 	if(i >= 0) {
 		sbi->cvf_format = cvf_formats[i];
 		++cvf_format_use_count[i];
 	}
 	return sb;
 
-out_no_root:
-	printk("FAT: get root inode failed\n");
-	iput(root_inode);
-	unload_nls(sbi->nls_io);
-out_unload_nls:
-	unload_nls(sbi->nls_disk);
-	goto out_fail;
 out_invalid:
-	if (!silent) {
-		printk("VFS: Can't find a valid FAT filesystem on dev %s.\n",
-			sb->s_id);
-	}
+	error = 0;
+
 out_fail:
-	if (opts.iocharset) {
-		printk("FAT: freeing iocharset=%s\n", opts.iocharset);
-		kfree(opts.iocharset);
-	}
-	if(sbi->private_data)
+	if (sbi->nls_io)
+		unload_nls(sbi->nls_io);
+	if (sbi->nls_disk)
+		unload_nls(sbi->nls_disk);
+	if (sbi->options.iocharset)
+		kfree(sbi->options.iocharset);
+	if (sbi->private_data)
 		kfree(sbi->private_data);
 	sbi->private_data = NULL;
- 
-	return NULL;
+
+	return ERR_PTR(error);
 }
 
 int fat_statfs(struct super_block *sb,struct statfs *buf)
@@ -882,7 +871,6 @@
 {
 	struct super_block *sb = inode->i_sb;
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
-	int nr;
 
 	INIT_LIST_HEAD(&MSDOS_I(inode)->i_fat_hash);
 	MSDOS_I(inode)->i_location = 0;
@@ -913,15 +901,7 @@
 			inode->i_nlink = 1;
 		}
 #endif
-		if ((nr = MSDOS_I(inode)->i_start) != 0)
-			while (nr != -1) {
-				inode->i_size += 1 << sbi->cluster_bits;
-				if (!(nr = fat_access(sb, nr, -1))) {
-					printk("Directory %ld: bad FAT\n",
-					    inode->i_ino);
-					break;
-				}
-			}
+		fat_calc_dir_size(inode);
 		MSDOS_I(inode)->mmu_private = inode->i_size;
 	} else { /* not a directory */
 		inode->i_generation |= 1;
diff -u --recursive --new-file v2.5.2/linux/fs/fat/misc.c linux/fs/fat/misc.c
--- v2.5.2/linux/fs/fat/misc.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/fat/misc.c	Tue Jan 15 10:58:53 2002
@@ -38,15 +38,25 @@
  * read-only. The file system can be made writable again by remounting it.
  */
 
-void fat_fs_panic(struct super_block *s,const char *msg)
+static char panic_msg[512];
+
+void fat_fs_panic(struct super_block *s, const char *fmt, ...)
 {
 	int not_ro;
+	va_list args;
+
+	va_start (args, fmt);
+	vsnprintf (panic_msg, sizeof(panic_msg), fmt, args);
+	va_end (args);
 
 	not_ro = !(s->s_flags & MS_RDONLY);
-	if (not_ro) s->s_flags |= MS_RDONLY;
-	printk("Filesystem panic (dev %s).\n  %s\n", s->s_id, msg);
 	if (not_ro)
-		printk("  File system has been set read-only\n");
+		s->s_flags |= MS_RDONLY;
+
+	printk("FAT: Filesystem panic (dev %s)\n"
+	       "    %s\n", s->s_id, panic_msg);
+	if (not_ro)
+		printk("    File system has been set read-only\n");
 }
 
 
@@ -102,13 +112,14 @@
 	/* Sanity check */
 	if (!IS_FSINFO(fsinfo)) {
 		printk("FAT: Did not find valid FSINFO signature.\n"
-		       "Found signature1 0x%x signature2 0x%x sector=%ld.\n",
+		       "     Found signature1 0x%08x signature2 0x%08x"
+		       " (sector = %lu)\n",
 		       CF_LE_L(fsinfo->signature1), CF_LE_L(fsinfo->signature2),
 		       MSDOS_SB(sb)->fsinfo_sector);
-		return;
+	} else {
+		fsinfo->free_clusters = CF_LE_L(MSDOS_SB(sb)->free_clusters);
+		fat_mark_buffer_dirty(sb, bh);
 	}
-	fsinfo->free_clusters = CF_LE_L(MSDOS_SB(sb)->free_clusters);
-	fat_mark_buffer_dirty(sb, bh);
 	fat_brelse(sb, bh);
 }
 
@@ -472,11 +483,13 @@
     int *number,int *ino,struct buffer_head **res_bh,struct msdos_dir_entry
     **res_de)
 {
-	int count,cluster;
+	int count, cluster;
+	unsigned long dir_size;
 
 #ifdef DEBUG
 	printk("raw_scan_nonroot: start=%d\n",start);
 #endif
+	dir_size = 0;
 	do {
 		for (count = 0; count < MSDOS_SB(sb)->cluster_size; count++) {
 			if ((cluster = raw_scan_sector(sb,(start-2)*
@@ -484,6 +497,13 @@
 			    count,name,number,ino,res_bh,res_de)) >= 0)
 				return cluster;
 		}
+		dir_size += 1 << MSDOS_SB(sb)->cluster_bits;
+		if (dir_size > FAT_MAX_DIR_SIZE) {
+			fat_fs_panic(sb, "Directory %d: "
+				     "exceeded the maximum size of directory",
+				     start);
+			break;
+		}
 		if (!(start = fat_access(sb,start,-1))) {
 			fat_fs_panic(sb,"FAT error");
 			break;
@@ -491,8 +511,8 @@
 #ifdef DEBUG
 	printk("next start: %d\n",start);
 #endif
-	}
-	while (start != -1);
+	} while (start != -1);
+
 	return -ENOENT;
 }
 
diff -u --recursive --new-file v2.5.2/linux/fs/fcntl.c linux/fs/fcntl.c
--- v2.5.2/linux/fs/fcntl.c	Mon Sep 17 13:16:30 2001
+++ linux/fs/fcntl.c	Tue Jan 15 11:07:01 2002
@@ -20,6 +20,28 @@
 extern int fcntl_setlease(unsigned int fd, struct file *filp, long arg);
 extern int fcntl_getlease(struct file *filp);
 
+void set_close_on_exec(unsigned int fd, int flag)
+{
+	struct files_struct *files = current->files;
+	write_lock(&files->file_lock);
+	if (flag)
+		FD_SET(fd, files->close_on_exec);
+	else
+		FD_CLR(fd, files->close_on_exec);
+	write_unlock(&files->file_lock);
+}
+
+static inline int get_close_on_exec(unsigned int fd)
+{
+	struct files_struct *files = current->files;
+	int res;
+	read_lock(&files->file_lock);
+	res = FD_ISSET(fd, files->close_on_exec);
+	read_unlock(&files->file_lock);
+	return res;
+}
+
+
 /* Expand files.  Return <0 on error; 0 nothing done; 1 files expanded,
  * we may have blocked. 
  *
diff -u --recursive --new-file v2.5.2/linux/fs/file.c linux/fs/file.c
--- v2.5.2/linux/fs/file.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/file.c	Tue Jan 15 11:07:01 2002
@@ -11,6 +11,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <linux/file.h>
 
 #include <asm/bitops.h>
 
diff -u --recursive --new-file v2.5.2/linux/fs/inode.c linux/fs/inode.c
--- v2.5.2/linux/fs/inode.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/inode.c	Thu Jan 17 14:30:00 2002
@@ -75,13 +75,53 @@
 
 static kmem_cache_t * inode_cachep;
 
-#define alloc_inode() \
-	 ((struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL))
+static struct inode *alloc_inode(struct super_block *sb)
+{
+	static struct address_space_operations empty_aops;
+	static struct inode_operations empty_iops;
+	static struct file_operations empty_fops;
+	struct inode *inode;
+
+	if (sb->s_op->alloc_inode)
+		inode = sb->s_op->alloc_inode(sb);
+	else
+		inode = (struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL);
+
+	if (inode) {
+		inode->i_sb = sb;
+		inode->i_dev = sb->s_dev;
+		inode->i_blkbits = sb->s_blocksize_bits;
+		inode->i_flags = 0;
+		atomic_set(&inode->i_count, 1);
+		inode->i_sock = 0;
+		inode->i_op = &empty_iops;
+		inode->i_fop = &empty_fops;
+		inode->i_nlink = 1;
+		atomic_set(&inode->i_writecount, 0);
+		inode->i_size = 0;
+		inode->i_blocks = 0;
+		inode->i_generation = 0;
+		memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
+		inode->i_pipe = NULL;
+		inode->i_bdev = NULL;
+		inode->i_cdev = NULL;
+		inode->i_data.a_ops = &empty_aops;
+		inode->i_data.host = inode;
+		inode->i_data.gfp_mask = GFP_HIGHUSER;
+		inode->i_mapping = &inode->i_data;
+		memset(&inode->u, 0, sizeof(inode->u));
+	}
+	return inode;
+}
+
 static void destroy_inode(struct inode *inode) 
 {
 	if (inode_has_buffers(inode))
 		BUG();
-	kmem_cache_free(inode_cachep, (inode));
+	if (inode->i_sb->s_op->destroy_inode)
+		inode->i_sb->s_op->destroy_inode(inode);
+	else
+		kmem_cache_free(inode_cachep, (inode));
 }
 
 
@@ -90,27 +130,30 @@
  * once, because the fields are idempotent across use
  * of the inode, so let the slab aware of that.
  */
+void inode_init_once(struct inode *inode)
+{
+	memset(inode, 0, sizeof(*inode));
+	init_waitqueue_head(&inode->i_wait);
+	INIT_LIST_HEAD(&inode->i_hash);
+	INIT_LIST_HEAD(&inode->i_data.clean_pages);
+	INIT_LIST_HEAD(&inode->i_data.dirty_pages);
+	INIT_LIST_HEAD(&inode->i_data.locked_pages);
+	INIT_LIST_HEAD(&inode->i_dentry);
+	INIT_LIST_HEAD(&inode->i_dirty_buffers);
+	INIT_LIST_HEAD(&inode->i_dirty_data_buffers);
+	INIT_LIST_HEAD(&inode->i_devices);
+	sema_init(&inode->i_sem, 1);
+	sema_init(&inode->i_zombie, 1);
+	spin_lock_init(&inode->i_data.i_shared_lock);
+}
+
 static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
 {
 	struct inode * inode = (struct inode *) foo;
 
 	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
 	    SLAB_CTOR_CONSTRUCTOR)
-	{
-		memset(inode, 0, sizeof(*inode));
-		init_waitqueue_head(&inode->i_wait);
-		INIT_LIST_HEAD(&inode->i_hash);
-		INIT_LIST_HEAD(&inode->i_data.clean_pages);
-		INIT_LIST_HEAD(&inode->i_data.dirty_pages);
-		INIT_LIST_HEAD(&inode->i_data.locked_pages);
-		INIT_LIST_HEAD(&inode->i_dentry);
-		INIT_LIST_HEAD(&inode->i_dirty_buffers);
-		INIT_LIST_HEAD(&inode->i_dirty_data_buffers);
-		INIT_LIST_HEAD(&inode->i_devices);
-		sema_init(&inode->i_sem, 1);
-		sema_init(&inode->i_zombie, 1);
-		spin_lock_init(&inode->i_data.i_shared_lock);
-	}
+		inode_init_once(inode);
 }
 
 /*
@@ -768,72 +811,28 @@
 	return inode;
 }
 
-/*
- * This just initializes the inode fields
- * to known values before returning the inode..
- *
- * i_sb, i_ino, i_count, i_state and the lists have
- * been initialized elsewhere..
- */
-static void clean_inode(struct inode *inode)
-{
-	static struct address_space_operations empty_aops;
-	static struct inode_operations empty_iops;
-	static struct file_operations empty_fops;
-	memset(&inode->u, 0, sizeof(inode->u));
-	inode->i_sock = 0;
-	inode->i_op = &empty_iops;
-	inode->i_fop = &empty_fops;
-	inode->i_nlink = 1;
-	atomic_set(&inode->i_writecount, 0);
-	inode->i_size = 0;
-	inode->i_blocks = 0;
-	inode->i_generation = 0;
-	memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
-	inode->i_pipe = NULL;
-	inode->i_bdev = NULL;
-	inode->i_cdev = NULL;
-	inode->i_data.a_ops = &empty_aops;
-	inode->i_data.host = inode;
-	inode->i_data.gfp_mask = GFP_HIGHUSER;
-	inode->i_mapping = &inode->i_data;
-}
-
 /**
- * get_empty_inode 	- obtain an inode
+ *	new_inode 	- obtain an inode
+ *	@sb: superblock
  *
- * This is called by things like the networking layer
- * etc that want to get an inode without any inode
- * number, or filesystems that allocate new inodes with
- * no pre-existing information.
- *
- * On a successful return the inode pointer is returned. On a failure
- * a %NULL pointer is returned. The returned inode is not on any superblock
- * lists.
+ *	Allocates a new inode for given superblock.
  */
  
-struct inode * get_empty_inode(void)
+struct inode *new_inode(struct super_block *sb)
 {
 	static unsigned long last_ino;
 	struct inode * inode;
 
 	spin_lock_prefetch(&inode_lock);
 	
-	inode = alloc_inode();
-	if (inode)
-	{
+	inode = alloc_inode(sb);
+	if (inode) {
 		spin_lock(&inode_lock);
 		inodes_stat.nr_inodes++;
 		list_add(&inode->i_list, &inode_in_use);
-		inode->i_sb = NULL;
-		inode->i_dev = NODEV;
-		inode->i_blkbits = 0;
 		inode->i_ino = ++last_ino;
-		inode->i_flags = 0;
-		atomic_set(&inode->i_count, 1);
 		inode->i_state = 0;
 		spin_unlock(&inode_lock);
-		clean_inode(inode);
 	}
 	return inode;
 }
@@ -848,7 +847,7 @@
 {
 	struct inode * inode;
 
-	inode = alloc_inode();
+	inode = alloc_inode(sb);
 	if (inode) {
 		struct inode * old;
 
@@ -859,16 +858,9 @@
 			inodes_stat.nr_inodes++;
 			list_add(&inode->i_list, &inode_in_use);
 			list_add(&inode->i_hash, head);
-			inode->i_sb = sb;
-			inode->i_dev = sb->s_dev;
-			inode->i_blkbits = sb->s_blocksize_bits;
 			inode->i_ino = ino;
-			inode->i_flags = 0;
-			atomic_set(&inode->i_count, 1);
 			inode->i_state = I_LOCK;
 			spin_unlock(&inode_lock);
-
-			clean_inode(inode);
 
 			/* reiserfs specific hack right here.  We don't
 			** want this to last, and are looking for VFS changes
diff -u --recursive --new-file v2.5.2/linux/fs/intermezzo/kml_reint.c linux/fs/intermezzo/kml_reint.c
--- v2.5.2/linux/fs/intermezzo/kml_reint.c	Sun Nov 11 10:20:21 2001
+++ linux/fs/intermezzo/kml_reint.c	Tue Jan 15 14:33:55 2002
@@ -17,7 +17,6 @@
 #include <linux/mm.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
-#include <asm/mmu_context.h>
 #include <linux/intermezzo_fs.h>
 #include <linux/intermezzo_kml.h>
 #include <linux/intermezzo_psdev.h>
diff -u --recursive --new-file v2.5.2/linux/fs/jbd/commit.c linux/fs/jbd/commit.c
--- v2.5.2/linux/fs/jbd/commit.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/jbd/commit.c	Tue Jan 15 13:53:51 2002
@@ -224,14 +224,13 @@
 		}
 	} while (jh != last_jh);
 
-	if (bufs || current->need_resched) {
+	if (bufs || need_resched()) {
 		jbd_debug(2, "submit %d writes\n", bufs);
 		spin_unlock(&journal_datalist_lock);
 		unlock_journal(journal);
 		if (bufs)
 			ll_rw_block(WRITE, bufs, wbuf);
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 		journal_brelse_array(wbuf, bufs);
 		lock_journal(journal);
 		spin_lock(&journal_datalist_lock);
@@ -458,8 +457,7 @@
 				bh->b_end_io = journal_end_buffer_io_sync;
 				submit_bh(WRITE, bh);
 			}
-			if (current->need_resched)
-				schedule();
+			cond_resched();
 			lock_journal(journal);
 
 			/* Force a new descriptor to be generated next
diff -u --recursive --new-file v2.5.2/linux/fs/jffs2/background.c linux/fs/jffs2/background.c
--- v2.5.2/linux/fs/jffs2/background.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/jffs2/background.c	Tue Jan 15 13:53:51 2002
@@ -127,8 +127,7 @@
 			schedule();
 		}
                 
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 
                 /* Put_super will send a SIGKILL and then wait on the sem. 
                  */
diff -u --recursive --new-file v2.5.2/linux/fs/jffs2/erase.c linux/fs/jffs2/erase.c
--- v2.5.2/linux/fs/jffs2/erase.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/jffs2/erase.c	Tue Jan 15 13:53:51 2002
@@ -131,8 +131,7 @@
 		
 		jffs2_erase_block(c, jeb);
 		/* Be nice */
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 		spin_lock_bh(&c->erase_completion_lock);
 	}
 	spin_unlock_bh(&c->erase_completion_lock);
diff -u --recursive --new-file v2.5.2/linux/fs/jffs2/nodemgmt.c linux/fs/jffs2/nodemgmt.c
--- v2.5.2/linux/fs/jffs2/nodemgmt.c	Thu Oct  4 15:13:18 2001
+++ linux/fs/jffs2/nodemgmt.c	Tue Jan 15 13:53:51 2002
@@ -101,8 +101,7 @@
 			if (ret)
 				return ret;
 
-			if (current->need_resched)
-				schedule();
+			cond_resched();
 
 			if (signal_pending(current))
 				return -EINTR;
diff -u --recursive --new-file v2.5.2/linux/fs/msdos/msdosfs_syms.c linux/fs/msdos/msdosfs_syms.c
--- v2.5.2/linux/fs/msdos/msdosfs_syms.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/msdos/msdosfs_syms.c	Wed Jan 16 10:20:23 2002
@@ -23,7 +23,6 @@
 EXPORT_SYMBOL(msdos_rename);
 EXPORT_SYMBOL(msdos_rmdir);
 EXPORT_SYMBOL(msdos_unlink);
-EXPORT_SYMBOL(msdos_read_super);
 EXPORT_SYMBOL(msdos_put_super);
 
 static DECLARE_FSTYPE_DEV(msdos_fs_type, "msdos", msdos_read_super);
diff -u --recursive --new-file v2.5.2/linux/fs/msdos/namei.c linux/fs/msdos/namei.c
--- v2.5.2/linux/fs/msdos/namei.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/msdos/namei.c	Wed Jan 16 10:20:23 2002
@@ -589,7 +589,15 @@
 
 	MSDOS_SB(sb)->options.isvfat = 0;
 	res = fat_read_super(sb, data, silent, &msdos_dir_inode_operations);
-	if (res)
-		sb->s_root->d_op = &msdos_dentry_operations;
+	if (IS_ERR(res))
+		return NULL;
+	if (res == NULL) {
+		if (!silent)
+			printk(KERN_INFO "VFS: Can't find a valid"
+			       " MSDOS filesystem on dev %s.\n", sb->s_id);
+		return NULL;
+	}
+
+	sb->s_root->d_op = &msdos_dentry_operations;
 	return res;
 }
diff -u --recursive --new-file v2.5.2/linux/fs/namei.c linux/fs/namei.c
--- v2.5.2/linux/fs/namei.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/namei.c	Tue Jan 15 13:53:51 2002
@@ -339,7 +339,7 @@
 		goto loop;
 	if (current->total_link_count >= 40)
 		goto loop;
-	if (current->need_resched) {
+	if (need_resched()) {
 		current->state = TASK_RUNNING;
 		schedule();
 	}
diff -u --recursive --new-file v2.5.2/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- v2.5.2/linux/fs/nfsd/vfs.c	Mon Jan 14 18:25:10 2002
+++ linux/fs/nfsd/vfs.c	Tue Jan 15 10:52:11 2002
@@ -560,9 +560,13 @@
 		return NULL;
 	rap = frap;
 	ra = *frap;
-	memset(ra, 0, sizeof(*ra));
 	ra->p_dev = dev;
 	ra->p_ino = ino;
+	ra->p_reada = 0;
+	ra->p_ramax = 0;
+	ra->p_raend = 0;
+	ra->p_ralen = 0;
+	ra->p_rawin = 0;
 found:
 	if (rap != &raparm_cache) {
 		*rap = ra->p_next;
diff -u --recursive --new-file v2.5.2/linux/fs/open.c linux/fs/open.c
--- v2.5.2/linux/fs/open.c	Fri Oct 12 13:48:42 2001
+++ linux/fs/open.c	Tue Jan 15 11:07:01 2002
@@ -772,6 +772,44 @@
 	return error;
 }
 
+static inline void __put_unused_fd(struct files_struct *files, unsigned int fd)
+{
+	__FD_CLR(fd, files->open_fds);
+	if (fd < files->next_fd)
+		files->next_fd = fd;
+}
+
+void put_unused_fd(unsigned int fd)
+{
+	struct files_struct *files = current->files;
+	write_lock(&files->file_lock);
+	__put_unused_fd(files, fd);
+	write_unlock(&files->file_lock);
+}
+
+/*
+ * Install a file pointer in the fd array.  
+ *
+ * The VFS is full of places where we drop the files lock between
+ * setting the open_fds bitmap and installing the file in the file
+ * array.  At any such point, we are vulnerable to a dup2() race
+ * installing a file in the array before us.  We need to detect this and
+ * fput() the struct file we are about to overwrite in this case.
+ *
+ * It should never happen - if we allow dup2() do it, _really_ bad things
+ * will follow.
+ */
+
+void fd_install(unsigned int fd, struct file * file)
+{
+	struct files_struct *files = current->files;
+	write_lock(&files->file_lock);
+	if (unlikely(files->fd[fd] != NULL))
+		BUG();
+	files->fd[fd] = file;
+	write_unlock(&files->file_lock);
+}
+
 asmlinkage long sys_open(const char * filename, int flags, int mode)
 {
 	char * tmp;
diff -u --recursive --new-file v2.5.2/linux/fs/partitions/Makefile linux/fs/partitions/Makefile
--- v2.5.2/linux/fs/partitions/Makefile	Thu Jul 26 16:30:04 2001
+++ linux/fs/partitions/Makefile	Tue Jan 15 11:27:47 2002
@@ -9,7 +9,7 @@
 
 O_TARGET := partitions.o
 
-export-objs := check.o ibm.o
+export-objs := check.o ibm.o msdos.o
 
 obj-y := check.o
 
diff -u --recursive --new-file v2.5.2/linux/fs/partitions/msdos.c linux/fs/partitions/msdos.c
--- v2.5.2/linux/fs/partitions/msdos.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/partitions/msdos.c	Tue Jan 15 11:27:47 2002
@@ -29,7 +29,13 @@
 
 #ifdef CONFIG_BLK_DEV_IDE
 #include <linux/ide.h>	/* IDE xlate */
-#endif /* CONFIG_BLK_DEV_IDE */
+#elif defined(CONFIG_BLK_DEV_IDE_MODULE)
+#include <linux/module.h>
+
+int (*ide_xlate_1024_hook)(kdev_t, int, int, const char *);
+EXPORT_SYMBOL(ide_xlate_1024_hook);
+#define ide_xlate_1024 ide_xlate_1024_hook
+#endif
 
 #include <asm/system.h>
 
@@ -468,7 +474,7 @@
  */
 static int handle_ide_mess(struct block_device *bdev)
 {
-#ifdef CONFIG_BLK_DEV_IDE
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 	Sector sect;
 	unsigned char *data;
 	kdev_t dev = to_kdev_t(bdev->bd_dev);
@@ -476,6 +482,10 @@
 	int heads = 0;
 	struct partition *p;
 	int i;
+#ifdef CONFIG_BLK_DEV_IDE_MODULE
+	if (!ide_xlate_1024)
+		return 1;
+#endif
 	/*
 	 * The i386 partition handling programs very often
 	 * make partitions end on cylinder boundaries.
@@ -537,7 +547,7 @@
 	/* Flush the cache */
 	invalidate_bdev(bdev, 1);
 	truncate_inode_pages(bdev->bd_inode->i_mapping, 0);
-#endif /* CONFIG_BLK_DEV_IDE */
+#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
 	return 1;
 }
  
diff -u --recursive --new-file v2.5.2/linux/fs/pipe.c linux/fs/pipe.c
--- v2.5.2/linux/fs/pipe.c	Fri Sep 28 18:03:48 2001
+++ linux/fs/pipe.c	Fri Jan 18 16:00:26 2002
@@ -608,16 +608,18 @@
 
 static struct super_block * pipefs_read_super(struct super_block *sb, void *data, int silent)
 {
-	struct inode *root = new_inode(sb);
+	struct inode *root;
+
+	sb->s_blocksize = 1024;
+	sb->s_blocksize_bits = 10;
+	sb->s_magic = PIPEFS_MAGIC;
+	sb->s_op	= &pipefs_ops;
+	root = new_inode(sb);
 	if (!root)
 		return NULL;
 	root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
 	root->i_uid = root->i_gid = 0;
 	root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
-	sb->s_blocksize = 1024;
-	sb->s_blocksize_bits = 10;
-	sb->s_magic = PIPEFS_MAGIC;
-	sb->s_op	= &pipefs_ops;
 	sb->s_root = d_alloc(NULL, &(const struct qstr) { "pipe:", 5, 0 });
 	if (!sb->s_root) {
 		iput(root);
diff -u --recursive --new-file v2.5.2/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.5.2/linux/fs/proc/array.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/proc/array.c	Tue Jan 15 11:07:01 2002
@@ -70,6 +70,7 @@
 #include <linux/smp.h>
 #include <linux/signal.h>
 #include <linux/highmem.h>
+#include <linux/file.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v2.5.2/linux/fs/reiserfs/inode.c linux/fs/reiserfs/inode.c
--- v2.5.2/linux/fs/reiserfs/inode.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/reiserfs/inode.c	Thu Jan 17 14:29:59 2002
@@ -101,9 +101,9 @@
 }
 
 static void add_to_flushlist(struct inode *inode, struct buffer_head *bh) {
-    struct inode *jinode = &(SB_JOURNAL(inode->i_sb)->j_dummy_inode) ;
+    struct list_head *list = &(SB_JOURNAL(inode->i_sb)->j_dirty_buffers) ;
 
-    buffer_insert_inode_queue(bh, jinode) ;
+    buffer_insert_list(bh, list) ;
 }
 
 //
@@ -808,8 +808,7 @@
 	/* inserting indirect pointers for a hole can take a 
 	** long time.  reschedule if needed
 	*/
-	if (current->need_resched)
-	    schedule() ;
+	cond_resched();
 
 	retval = search_for_position_by_key (inode->i_sb, &key, &path);
 	if (retval == IO_ERROR) {
diff -u --recursive --new-file v2.5.2/linux/fs/reiserfs/journal.c linux/fs/reiserfs/journal.c
--- v2.5.2/linux/fs/reiserfs/journal.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/reiserfs/journal.c	Thu Jan 17 14:29:59 2002
@@ -1897,7 +1897,7 @@
   memset(journal_writers, 0, sizeof(char *) * 512) ; /* debug code */
 
   INIT_LIST_HEAD(&SB_JOURNAL(p_s_sb)->j_bitmap_nodes) ;
-  INIT_LIST_HEAD(&(SB_JOURNAL(p_s_sb)->j_dummy_inode.i_dirty_buffers)) ;
+  INIT_LIST_HEAD(&SB_JOURNAL(p_s_sb)->j_dirty_buffers) ;
   reiserfs_allocate_list_bitmaps(p_s_sb, SB_JOURNAL(p_s_sb)->j_list_bitmap, 
                                  SB_BMAP_NR(p_s_sb)) ;
   allocate_bitmap_nodes(p_s_sb) ;
@@ -2902,7 +2902,7 @@
   SB_JOURNAL_LIST_INDEX(p_s_sb) = jindex ;
 
   /* write any buffers that must hit disk before this commit is done */
-  fsync_inode_buffers(&(SB_JOURNAL(p_s_sb)->j_dummy_inode)) ;
+  fsync_buffers_list(&(SB_JOURNAL(p_s_sb)->j_dirty_buffers)) ;
 
   /* honor the flush and async wishes from the caller */
   if (flush) {
diff -u --recursive --new-file v2.5.2/linux/fs/umsdos/inode.c linux/fs/umsdos/inode.c
--- v2.5.2/linux/fs/umsdos/inode.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/umsdos/inode.c	Wed Jan 16 10:20:23 2002
@@ -363,10 +363,17 @@
 	 * Call msdos-fs to mount the disk.
 	 * Note: this returns res == sb or NULL
 	 */
-	res = msdos_read_super (sb, data, silent);
+	MSDOS_SB(sb)->options.isvfat = 0;
+	res = fat_read_super(sb, data, silent, &umsdos_rdir_inode_operations);
 
-	if (!res)
-		goto out_fail;
+	if (IS_ERR(res))
+		return NULL;
+	if (res == NULL) {
+		if (!silent)
+			printk(KERN_INFO "VFS: Can't find a valid "
+			       "UMSDOS filesystem on dev %s.\n", sb->s_id);
+		return NULL;
+	}
 
 	printk (KERN_INFO "UMSDOS 0.86k "
 		"(compatibility level %d.%d, fast msdos)\n", 
@@ -394,10 +401,6 @@
 		dget (sb->s_root); sb->s_root = dget(new_root);
 	}
 	return sb;
-
-out_fail:
-	printk(KERN_INFO "UMSDOS: msdos_read_super failed, mount aborted.\n");
-	return NULL;
 }
 
 /*
diff -u --recursive --new-file v2.5.2/linux/fs/vfat/namei.c linux/fs/vfat/namei.c
--- v2.5.2/linux/fs/vfat/namei.c	Mon Jan 14 18:25:11 2002
+++ linux/fs/vfat/namei.c	Wed Jan 16 10:20:23 2002
@@ -446,7 +446,7 @@
 	(x)->lower = 1;				\
 	(x)->upper = 1;				\
 	(x)->valid = 1;				\
-} while (0);
+} while (0)
 
 static inline unsigned char
 shortname_info_to_lcase(struct shortname_info *base,
@@ -1266,10 +1266,15 @@
 	struct super_block *res;
   
 	MSDOS_SB(sb)->options.isvfat = 1;
-
 	res = fat_read_super(sb, data, silent, &vfat_dir_inode_operations);
-	if (res == NULL)
+	if (IS_ERR(res))
+		return NULL;
+	if (res == NULL) {
+		if (!silent)
+			printk(KERN_INFO "VFS: Can't find a valid"
+			       " VFAT filesystem on dev %s.\n", sb->s_id);
 		return NULL;
+	}
 
 	if (parse_options((char *) data, &(MSDOS_SB(sb)->options))) {
 		MSDOS_SB(sb)->options.dotsOK = 0;
diff -u --recursive --new-file v2.5.2/linux/include/asm-alpha/ide.h linux/include/asm-alpha/ide.h
--- v2.5.2/linux/include/asm-alpha/ide.h	Wed May 24 08:40:41 2000
+++ linux/include/asm-alpha/ide.h	Tue Jan 15 11:27:47 2002
@@ -91,7 +91,19 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 #define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
 #define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
diff -u --recursive --new-file v2.5.2/linux/include/asm-alpha/pci.h linux/include/asm-alpha/pci.h
--- v2.5.2/linux/include/asm-alpha/pci.h	Fri Oct 12 15:35:54 2001
+++ linux/include/asm-alpha/pci.h	Tue Jan 15 11:48:13 2002
@@ -101,6 +101,20 @@
 extern void pci_unmap_single(struct pci_dev *, dma_addr_t, size_t, int);
 extern void pci_unmap_page(struct pci_dev *, dma_addr_t, size_t, int);
 
+/* pci_unmap_{single,page} is not a nop, thus... */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)	\
+	dma_addr_t ADDR_NAME;
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)		\
+	__u32 LEN_NAME;
+#define pci_unmap_addr(PTR, ADDR_NAME)			\
+	((PTR)->ADDR_NAME)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)		\
+	(((PTR)->ADDR_NAME) = (VAL))
+#define pci_unmap_len(PTR, LEN_NAME)			\
+	((PTR)->LEN_NAME)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)		\
+	(((PTR)->LEN_NAME) = (VAL))
+
 /* Map a set of buffers described by scatterlist in streaming mode for
    PCI DMA.  This is the scather-gather version of the above
    pci_map_single interface.  Here the scatter gather list elements
diff -u --recursive --new-file v2.5.2/linux/include/asm-alpha/pgalloc.h linux/include/asm-alpha/pgalloc.h
--- v2.5.2/linux/include/asm-alpha/pgalloc.h	Thu May 24 15:20:18 2001
+++ linux/include/asm-alpha/pgalloc.h	Tue Jan 15 10:56:35 2002
@@ -14,7 +14,7 @@
 /* Caches aren't brain-dead on the Alpha. */
 #define flush_cache_all()			do { } while (0)
 #define flush_cache_mm(mm)			do { } while (0)
-#define flush_cache_range(mm, start, end)	do { } while (0)
+#define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr)		do { } while (0)
 #define flush_page_to_ram(page)			do { } while (0)
 #define flush_dcache_page(page)			do { } while (0)
@@ -206,10 +206,10 @@
  * Flush a specified range of user mapping:  on the
  * Alpha we flush the whole user tlb.
  */
-static inline void flush_tlb_range(struct mm_struct *mm,
+static inline void flush_tlb_range(struct vm_area_struct *vma,
 	unsigned long start, unsigned long end)
 {
-	flush_tlb_mm(mm);
+	flush_tlb_mm(vma->vm_mm);
 }
 
 #else /* CONFIG_SMP */
@@ -217,7 +217,7 @@
 extern void flush_tlb_all(void);
 extern void flush_tlb_mm(struct mm_struct *);
 extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
-extern void flush_tlb_range(struct mm_struct *, unsigned long, unsigned long);
+extern void flush_tlb_range(struct vm_area_struct *, unsigned long, unsigned long);
 
 #endif /* CONFIG_SMP */
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-alpha/pgtable.h linux/include/asm-alpha/pgtable.h
--- v2.5.2/linux/include/asm-alpha/pgtable.h	Thu Oct 25 14:00:32 2001
+++ linux/include/asm-alpha/pgtable.h	Tue Jan 15 10:56:35 2002
@@ -344,8 +344,8 @@
 #define kern_addr_valid(addr)	(1)
 #endif
 
-#define io_remap_page_range(start, busaddr, size, prot) \
-    remap_page_range(start, virt_to_phys(__ioremap(busaddr, size)), size, prot)
+#define io_remap_page_range(vma, start, busaddr, size, prot) \
+    remap_page_range(vma, start, virt_to_phys(__ioremap(busaddr, size)), size, prot)
 
 #define pte_ERROR(e) \
 	printk("%s:%d: bad pte %016lx.\n", __FILE__, __LINE__, pte_val(e))
diff -u --recursive --new-file v2.5.2/linux/include/asm-arm/arch-arc/system.h linux/include/asm-arm/arch-arc/system.h
--- v2.5.2/linux/include/asm-arm/arch-arc/system.h	Sun Aug 12 11:14:00 2001
+++ linux/include/asm-arm/arch-arc/system.h	Tue Jan 15 13:53:51 2002
@@ -10,7 +10,7 @@
 
 static void arch_idle(void)
 {
-	while (!current->need_resched && !hlt_counter);
+	while (!need_resched() && !hlt_counter);
 }
 
 static inline void arch_reset(char mode)
diff -u --recursive --new-file v2.5.2/linux/include/asm-arm/arch-cl7500/system.h linux/include/asm-arm/arch-cl7500/system.h
--- v2.5.2/linux/include/asm-arm/arch-cl7500/system.h	Thu Apr 12 12:20:31 2001
+++ linux/include/asm-arm/arch-cl7500/system.h	Tue Jan 15 13:53:51 2002
@@ -10,7 +10,7 @@
 
 static void arch_idle(void)
 {
-	while (!current->need_resched && !hlt_counter)
+	while (!need_resched() && !hlt_counter)
 		iomd_writeb(0, IOMD_SUSMODE);
 }
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-arm/arch-ebsa110/system.h linux/include/asm-arm/arch-ebsa110/system.h
--- v2.5.2/linux/include/asm-arm/arch-ebsa110/system.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/arch-ebsa110/system.h	Tue Jan 15 13:53:51 2002
@@ -17,7 +17,7 @@
  * will stop our MCLK signal (which provides the clock for the glue
  * logic, and therefore the timer interrupt).
  *
- * Instead, we spin, waiting for either hlt_counter or need_resched
+ * Instead, we spin, waiting for either hlt_counter or need_resched()
  * to be set.  If we have been spinning for 2cs, then we drop the
  * core clock down to the memory clock.
  */
@@ -28,13 +28,13 @@
 	start_idle = jiffies;
 
 	do {
-		if (current->need_resched || hlt_counter)
+		if (need_resched() || hlt_counter)
 			goto slow_out;
 	} while (time_before(jiffies, start_idle + HZ/50));
 
 	cpu_do_idle(IDLE_CLOCK_SLOW);
 
-	while (!current->need_resched && !hlt_counter) {
+	while (!need_resched() && !hlt_counter) {
 		/* do nothing slowly */
 	}
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-arm/arch-ebsa285/system.h linux/include/asm-arm/arch-ebsa285/system.h
--- v2.5.2/linux/include/asm-arm/arch-ebsa285/system.h	Sun Aug 12 11:14:00 2001
+++ linux/include/asm-arm/arch-ebsa285/system.h	Tue Jan 15 13:53:51 2002
@@ -20,14 +20,14 @@
 	start_idle = jiffies;
 
 	do {
-		if (current->need_resched || hlt_counter)
+		if (need_resched() || hlt_counter)
 			goto slow_out;
 		cpu_do_idle(IDLE_WAIT_FAST);
 	} while (time_before(jiffies, start_idle + HZ/50));
 
 	cpu_do_idle(IDLE_CLOCK_SLOW);
 
-	while (!current->need_resched && !hlt_counter) {
+	while (!need_resched() && !hlt_counter) {
 		cpu_do_idle(IDLE_WAIT_SLOW);
 	}
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-arm/arch-nexuspci/system.h linux/include/asm-arm/arch-nexuspci/system.h
--- v2.5.2/linux/include/asm-arm/arch-nexuspci/system.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/arch-nexuspci/system.h	Tue Jan 15 13:53:51 2002
@@ -16,7 +16,7 @@
 
 static void arch_idle(void)
 {
-	while (!current->need_resched && !hlt_counter)
+	while (!need_resched() && !hlt_counter)
 		cpu_do_idle(IDLE_WAIT_SLOW);
 }
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-arm/arch-rpc/system.h linux/include/asm-arm/arch-rpc/system.h
--- v2.5.2/linux/include/asm-arm/arch-rpc/system.h	Sun Aug 12 11:14:00 2001
+++ linux/include/asm-arm/arch-rpc/system.h	Tue Jan 15 13:53:51 2002
@@ -18,14 +18,14 @@
 	start_idle = jiffies;
 
 	do {
-		if (current->need_resched || hlt_counter)
+		if (need_resched() || hlt_counter)
 			goto slow_out;
 		cpu_do_idle(IDLE_WAIT_FAST);
 	} while (time_before(jiffies, start_idle + HZ/50));
 
 	cpu_do_idle(IDLE_CLOCK_SLOW);
 
-	while (!current->need_resched && !hlt_counter) {
+	while (!need_resched() && !hlt_counter) {
 		cpu_do_idle(IDLE_WAIT_SLOW);
 	}
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-arm/arch-sa1100/system.h linux/include/asm-arm/arch-sa1100/system.h
--- v2.5.2/linux/include/asm-arm/arch-sa1100/system.h	Thu Oct 25 13:53:54 2001
+++ linux/include/asm-arm/arch-sa1100/system.h	Tue Jan 15 13:53:51 2002
@@ -10,7 +10,7 @@
 	if (!hlt_counter) {
 		int flags;
 		local_irq_save(flags);
-		if (!current->need_resched)
+		if (!need_resched())
 			cpu_do_idle(0);
 		local_irq_restore(flags);
 	}
diff -u --recursive --new-file v2.5.2/linux/include/asm-arm/arch-tbox/system.h linux/include/asm-arm/arch-tbox/system.h
--- v2.5.2/linux/include/asm-arm/arch-tbox/system.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/arch-tbox/system.h	Tue Jan 15 13:53:51 2002
@@ -13,14 +13,14 @@
 	start_idle = jiffies;
 
 	do {
-		if (current->need_resched || hlt_counter)
+		if (need_resched() || hlt_counter)
 			goto slow_out;
 		cpu_do_idle(IDLE_WAIT_FAST);
 	} while (time_before(jiffies, start_idle + HZ/50));
 
 	cpu_do_idle(IDLE_CLOCK_SLOW);
 
-	while (!current->need_resched && !hlt_counter) {
+	while (!need_resched() && !hlt_counter) {
 		cpu_do_idle(IDLE_WAIT_SLOW);
 	}
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-arm/ide.h linux/include/asm-arm/ide.h
--- v2.5.2/linux/include/asm-arm/ide.h	Thu Jun 17 01:11:35 1999
+++ linux/include/asm-arm/ide.h	Tue Jan 15 11:27:47 2002
@@ -30,7 +30,19 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 #define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
 #define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
diff -u --recursive --new-file v2.5.2/linux/include/asm-arm/pci.h linux/include/asm-arm/pci.h
--- v2.5.2/linux/include/asm-arm/pci.h	Mon Jan 14 18:25:11 2002
+++ linux/include/asm-arm/pci.h	Tue Jan 15 11:48:13 2002
@@ -95,6 +95,31 @@
 	/* nothing to do */
 }
 
+/* Whether pci_unmap_{single,page} is a nop depends upon the
+ * configuration.
+ */
+#ifdef CONFIG_SA1111
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)	\
+	dma_addr_t ADDR_NAME;
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)		\
+	__u32 LEN_NAME;
+#define pci_unmap_addr(PTR, ADDR_NAME)			\
+	((PTR)->ADDR_NAME)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)		\
+	(((PTR)->ADDR_NAME) = (VAL))
+#define pci_unmap_len(PTR, LEN_NAME)			\
+	((PTR)->LEN_NAME)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)		\
+	(((PTR)->LEN_NAME) = (VAL))
+#else /* !(CONFIG_SA1111) */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
+#define pci_unmap_addr(PTR, ADDR_NAME)		(0)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)	do { } while (0)
+#define pci_unmap_len(PTR, LEN_NAME)		(0)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)	do { } while (0)
+#endif /* CONFIG_SA1111 */
+
 /* Map a set of buffers described by scatterlist in streaming
  * mode for DMA.  This is the scather-gather version of the
  * above pci_map_single interface.  Here the scatter gather list
diff -u --recursive --new-file v2.5.2/linux/include/asm-arm/pgtable.h linux/include/asm-arm/pgtable.h
--- v2.5.2/linux/include/asm-arm/pgtable.h	Mon Jan 14 18:25:11 2002
+++ linux/include/asm-arm/pgtable.h	Tue Jan 15 10:56:35 2002
@@ -182,8 +182,8 @@
  * remap a physical address `phys' of size `size' with page protection `prot'
  * into virtual address `from'
  */
-#define io_remap_page_range(from,phys,size,prot) \
-		remap_page_range(from,phys,size,prot)
+#define io_remap_page_range(vma,from,phys,size,prot) \
+		remap_page_range(vma,from,phys,size,prot)
 
 #endif /* !__ASSEMBLY__ */
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-arm/proc-armo/cache.h linux/include/asm-arm/proc-armo/cache.h
--- v2.5.2/linux/include/asm-arm/proc-armo/cache.h	Sun Aug 12 11:14:00 2001
+++ linux/include/asm-arm/proc-armo/cache.h	Tue Jan 15 10:56:35 2002
@@ -11,7 +11,7 @@
  */
 #define flush_cache_all()			do { } while (0)
 #define flush_cache_mm(mm)			do { } while (0)
-#define flush_cache_range(mm,start,end)		do { } while (0)
+#define flush_cache_range(vma,start,end)	do { } while (0)
 #define flush_cache_page(vma,vmaddr)		do { } while (0)
 #define flush_page_to_ram(page)			do { } while (0)
 
@@ -34,12 +34,12 @@
  *  - flush_tlb_all() flushes all processes TLBs
  *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
  *  - flush_tlb_page(vma, vmaddr) flushes one page
- *  - flush_tlb_range(mm, start, end) flushes a range of pages
+ *  - flush_tlb_range(vma, start, end) flushes a range of pages
  */
 #define flush_tlb_all()				memc_update_all()
 #define flush_tlb_mm(mm)			memc_update_mm(mm)
-#define flush_tlb_range(mm,start,end)		\
-		do { memc_update_mm(mm); (void)(start); (void)(end); } while (0)
+#define flush_tlb_range(vma,start,end)		\
+		do { memc_update_mm(vma->vm_mm); (void)(start); (void)(end); } while (0)
 #define flush_tlb_page(vma, vmaddr)		do { } while (0)
 
 /*
diff -u --recursive --new-file v2.5.2/linux/include/asm-arm/proc-armv/cache.h linux/include/asm-arm/proc-armv/cache.h
--- v2.5.2/linux/include/asm-arm/proc-armv/cache.h	Mon Jan 14 18:25:11 2002
+++ linux/include/asm-arm/proc-armv/cache.h	Tue Jan 15 10:56:35 2002
@@ -42,9 +42,9 @@
 			cpu_cache_clean_invalidate_all();		\
 	} while (0)
 
-#define flush_cache_range(_mm,_start,_end)				\
+#define flush_cache_range(_vma,_start,_end)				\
 	do {								\
-		if ((_mm) == current->active_mm)			\
+		if ((_vma)->vm_mm == current->active_mm)		\
 			cpu_cache_clean_invalidate_range((_start), (_end), 1); \
 	} while (0)
 
@@ -214,7 +214,7 @@
  *  - flush_tlb_all()			flushes all processes TLBs
  *  - flush_tlb_mm(mm)			flushes the specified mm context TLB's
  *  - flush_tlb_page(vma, vmaddr)	flushes TLB for specified page
- *  - flush_tlb_range(mm, start, end)	flushes TLB for specified range of pages
+ *  - flush_tlb_range(vma, start, end)	flushes TLB for specified range of pages
  *
  * We drain the write buffer in here to ensure that the page tables in ram
  * are really up to date.  It is more efficient to do this here...
@@ -248,9 +248,9 @@
  *
  * _mm may not be current->active_mm, but may not be NULL.
  */
-#define flush_tlb_range(_mm,_start,_end)				\
+#define flush_tlb_range(_vma,_start,_end)				\
 	do {								\
-		if ((_mm) == current->active_mm)			\
+		if ((_mm)->vm_mm == current->active_mm)			\
 			cpu_tlb_invalidate_range((_start), (_end));	\
 	} while (0)
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-cris/ide.h linux/include/asm-cris/ide.h
--- v2.5.2/linux/include/asm-cris/ide.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-cris/ide.h	Tue Jan 15 11:27:47 2002
@@ -97,7 +97,19 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 /* some configuration options we don't need */
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-cris/pgtable.h linux/include/asm-cris/pgtable.h
--- v2.5.2/linux/include/asm-cris/pgtable.h	Fri Nov  9 14:11:15 2001
+++ linux/include/asm-cris/pgtable.h	Tue Jan 15 10:56:35 2002
@@ -111,7 +111,7 @@
  */
 #define flush_cache_all()			do { } while (0)
 #define flush_cache_mm(mm)			do { } while (0)
-#define flush_cache_range(mm, start, end)	do { } while (0)
+#define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr)		do { } while (0)
 #define flush_page_to_ram(page)			do { } while (0)
 #define flush_dcache_page(page)                 do { } while (0)
@@ -125,7 +125,7 @@
  *  - flush_tlb_all() flushes all processes TLBs
  *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
  *  - flush_tlb_page(vma, vmaddr) flushes one page
- *  - flush_tlb_range(mm, start, end) flushes a range of pages
+ *  - flush_tlb_range(vma, start, end) flushes a range of pages
  *
  */
 
@@ -133,7 +133,7 @@
 extern void flush_tlb_mm(struct mm_struct *mm);
 extern void flush_tlb_page(struct vm_area_struct *vma, 
 			   unsigned long addr);
-extern void flush_tlb_range(struct mm_struct *mm,
+extern void flush_tlb_range(struct vm_area_struct *vma,
 			    unsigned long start,
 			    unsigned long end);
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-generic/tlb.h linux/include/asm-generic/tlb.h
--- v2.5.2/linux/include/asm-generic/tlb.h	Fri Sep 14 08:41:04 2001
+++ linux/include/asm-generic/tlb.h	Tue Jan 15 10:56:35 2002
@@ -25,7 +25,7 @@
  * shootdown.
  */
 typedef struct free_pte_ctx {
-	struct mm_struct	*mm;
+	struct vm_area_struct	*vma;
 	unsigned long		nr;	/* set to ~0UL means fast mode */
 	unsigned long	start_addr, end_addr;
 	pte_t	ptes[FREE_PTE_NR];
@@ -37,11 +37,12 @@
 /* tlb_gather_mmu
  *	Return a pointer to an initialized mmu_gather_t.
  */
-static inline mmu_gather_t *tlb_gather_mmu(struct mm_struct *mm)
+static inline mmu_gather_t *tlb_gather_mmu(struct vm_area_struct *vma)
 {
 	mmu_gather_t *tlb = &mmu_gathers[smp_processor_id()];
+	struct mm_struct *mm = vma->vm_mm;
 
-	tlb->mm = mm;
+	tlb->vma = vma;
 	/* Use fast mode if there is only one user of this mm (this process) */
 	tlb->nr = (atomic_read(&(mm)->mm_users) == 1) ? ~0UL : 0UL;
 	return tlb;
@@ -69,7 +70,7 @@
 
 /* tlb_finish_mmu
  *	Called at the end of the shootdown operation to free up any resources
- *	that were required.  The page talbe lock is still held at this point.
+ *	that were required.  The page table lock is still held at this point.
  */
 static inline void tlb_finish_mmu(struct free_pte_ctx *ctx, unsigned long start, unsigned long end)
 {
@@ -77,13 +78,13 @@
 
 	/* Handle the fast case first. */
 	if (ctx->nr == ~0UL) {
-		flush_tlb_range(ctx->mm, start, end);
+		flush_tlb_range(ctx->vma, start, end);
 		return;
 	}
 	nr = ctx->nr;
 	ctx->nr = 0;
 	if (nr)
-		flush_tlb_range(ctx->mm, ctx->start_addr, ctx->end_addr);
+		flush_tlb_range(ctx->vma, ctx->start_addr, ctx->end_addr);
 	for (i=0; i < nr; i++) {
 		pte_t pte = ctx->ptes[i];
 		__free_pte(pte);
@@ -96,9 +97,9 @@
  * attempt to get gcc to generate optimal code since this code is run on each
  * page in a process at exit.
  */
-typedef struct mm_struct mmu_gather_t;
+typedef struct vm_area_struct mmu_gather_t;
 
-#define tlb_gather_mmu(mm)	(mm)
+#define tlb_gather_mmu(vma)	(vma)
 #define tlb_finish_mmu(tlb, start, end)	flush_tlb_range(tlb, start, end)
 #define tlb_remove_page(tlb, ptep, addr)	do {\
 		pte_t __pte = *(ptep);\
diff -u --recursive --new-file v2.5.2/linux/include/asm-i386/ide.h linux/include/asm-i386/ide.h
--- v2.5.2/linux/include/asm-i386/ide.h	Thu Nov 22 11:46:58 2001
+++ linux/include/asm-i386/ide.h	Sat Jan 19 14:30:41 2002
@@ -95,7 +95,19 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 #define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
 #define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
diff -u --recursive --new-file v2.5.2/linux/include/asm-i386/mmu_context.h linux/include/asm-i386/mmu_context.h
--- v2.5.2/linux/include/asm-i386/mmu_context.h	Mon Jan 14 18:25:11 2002
+++ linux/include/asm-i386/mmu_context.h	Sat Jan 19 14:31:46 2002
@@ -1,5 +1,5 @@
-#ifndef __I386_MMU_CONTEXT_H
-#define __I386_MMU_CONTEXT_H
+#ifndef __I386_SCHED_H
+#define __I386_SCHED_H
 
 #include <linux/config.h>
 #include <asm/desc.h>
@@ -16,14 +16,13 @@
 # error update this function.
 #endif
 
-static inline int sched_find_first_zero_bit(char *bitmap)
+static inline int sched_find_first_zero_bit(unsigned long *b)
 {
-	unsigned int *b = (unsigned int *)bitmap;
 	unsigned int rt;
 
 	rt = b[0] & b[1] & b[2] & b[3];
 	if (unlikely(rt != 0xffffffff))
-		return find_first_zero_bit(bitmap, MAX_RT_PRIO);
+		return find_first_zero_bit(b, MAX_RT_PRIO);
 
 	if (b[4] != ~0)
 		return ffz(b[4]) + MAX_RT_PRIO;
diff -u --recursive --new-file v2.5.2/linux/include/asm-i386/pci.h linux/include/asm-i386/pci.h
--- v2.5.2/linux/include/asm-i386/pci.h	Thu Nov 22 11:46:29 2001
+++ linux/include/asm-i386/pci.h	Sat Jan 19 14:30:27 2002
@@ -114,6 +114,14 @@
 	/* Nothing to do */
 }
 
+/* pci_unmap_{page,single} is a nop so... */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
+#define pci_unmap_addr(PTR, ADDR_NAME)		(0)
+#define pci_unmap_addr_SET(PTR, ADDR_NAME, VAL)	do { } while (0)
+#define pci_unmap_len(PTR, LEN_NAME)		(0)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)	do { } while (0)
+
 /* Map a set of buffers described by scatterlist in streaming
  * mode for DMA.  This is the scather-gather version of the
  * above pci_map_single interface.  Here the scatter gather list
diff -u --recursive --new-file v2.5.2/linux/include/asm-i386/pgalloc.h linux/include/asm-i386/pgalloc.h
--- v2.5.2/linux/include/asm-i386/pgalloc.h	Mon Jan 14 18:25:11 2002
+++ linux/include/asm-i386/pgalloc.h	Sat Jan 19 14:30:01 2002
@@ -165,7 +165,7 @@
  *  - flush_tlb_all() flushes all processes TLBs
  *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
  *  - flush_tlb_page(vma, vmaddr) flushes one page
- *  - flush_tlb_range(mm, start, end) flushes a range of pages
+ *  - flush_tlb_range(vma, start, end) flushes a range of pages
  *  - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
  *
  * ..but the i386 has somewhat limited tlb flushing capabilities,
@@ -191,10 +191,10 @@
 		__flush_tlb_one(addr);
 }
 
-static inline void flush_tlb_range(struct mm_struct *mm,
+static inline void flush_tlb_range(struct vm_area_struct *vma,
 	unsigned long start, unsigned long end)
 {
-	if (mm == current->active_mm)
+	if (vma->vm_mm == current->active_mm)
 		__flush_tlb();
 }
 
@@ -212,9 +212,9 @@
 
 #define flush_tlb()	flush_tlb_current_task()
 
-static inline void flush_tlb_range(struct mm_struct * mm, unsigned long start, unsigned long end)
+static inline void flush_tlb_range(struct vm_area_struct * vma, unsigned long start, unsigned long end)
 {
-	flush_tlb_mm(mm);
+	flush_tlb_mm(vma->vm_mm);
 }
 
 #define TLBSTATE_OK	1
diff -u --recursive --new-file v2.5.2/linux/include/asm-i386/pgtable.h linux/include/asm-i386/pgtable.h
--- v2.5.2/linux/include/asm-i386/pgtable.h	Thu Nov 22 11:46:19 2001
+++ linux/include/asm-i386/pgtable.h	Sat Jan 19 14:29:58 2002
@@ -27,7 +27,7 @@
 /* Caches aren't brain-dead on the intel. */
 #define flush_cache_all()			do { } while (0)
 #define flush_cache_mm(mm)			do { } while (0)
-#define flush_cache_range(mm, start, end)	do { } while (0)
+#define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr)		do { } while (0)
 #define flush_page_to_ram(page)			do { } while (0)
 #define flush_dcache_page(page)			do { } while (0)
diff -u --recursive --new-file v2.5.2/linux/include/asm-i386/smplock.h linux/include/asm-i386/smplock.h
--- v2.5.2/linux/include/asm-i386/smplock.h	Mon Jan 14 18:25:11 2002
+++ linux/include/asm-i386/smplock.h	Sat Jan 19 14:30:03 2002
@@ -19,8 +19,8 @@
 do {						\
 	if (unlikely(task->lock_depth >= 0)) {	\
 		spin_unlock(&kernel_flag);	\
-		release_irqlock(cpu);		\
-		__sti();			\
+		if (global_irq_holder == (cpu))	\
+			BUG();			\
 	}					\
 } while (0)
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-ia64/ide.h linux/include/asm-ia64/ide.h
--- v2.5.2/linux/include/asm-ia64/ide.h	Wed May 24 08:40:41 2000
+++ linux/include/asm-ia64/ide.h	Tue Jan 15 11:27:47 2002
@@ -101,7 +101,19 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 #define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
 #define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
diff -u --recursive --new-file v2.5.2/linux/include/asm-ia64/pci.h linux/include/asm-ia64/pci.h
--- v2.5.2/linux/include/asm-ia64/pci.h	Fri Nov  9 14:26:17 2001
+++ linux/include/asm-ia64/pci.h	Tue Jan 15 11:48:13 2002
@@ -46,6 +46,20 @@
 #define pci_dma_sync_sg			platform_pci_dma_sync_sg
 #define sg_dma_address			platform_pci_dma_address
 
+/* pci_unmap_{single,page} is not a nop, thus... */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)	\
+	dma_addr_t ADDR_NAME;
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)		\
+	__u32 LEN_NAME;
+#define pci_unmap_addr(PTR, ADDR_NAME)			\
+	((PTR)->ADDR_NAME)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)		\
+	(((PTR)->ADDR_NAME) = (VAL))
+#define pci_unmap_len(PTR, LEN_NAME)			\
+	((PTR)->LEN_NAME)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)		\
+	(((PTR)->LEN_NAME) = (VAL))
+
 /*
  * Return whether the given PCI device DMA address mask can be supported properly.  For
  * example, if your device can only drive the low 24-bits during PCI bus mastering, then
diff -u --recursive --new-file v2.5.2/linux/include/asm-ia64/pgalloc.h linux/include/asm-ia64/pgalloc.h
--- v2.5.2/linux/include/asm-ia64/pgalloc.h	Fri Nov  9 14:26:17 2001
+++ linux/include/asm-ia64/pgalloc.h	Tue Jan 15 10:56:36 2002
@@ -181,7 +181,7 @@
 	}
 }
 
-extern void flush_tlb_range (struct mm_struct *mm, unsigned long start, unsigned long end);
+extern void flush_tlb_range (struct vm_area_struct *vma, unsigned long start, unsigned long end);
 
 /*
  * Page-granular tlb flush.
@@ -190,7 +190,7 @@
 flush_tlb_page (struct vm_area_struct *vma, unsigned long addr)
 {
 #ifdef CONFIG_SMP
-	flush_tlb_range(vma->vm_mm, (addr & PAGE_MASK), (addr & PAGE_MASK) + PAGE_SIZE);
+	flush_tlb_range(vma, (addr & PAGE_MASK), (addr & PAGE_MASK) + PAGE_SIZE);
 #else
 	if (vma->vm_mm == current->active_mm)
 		asm volatile ("ptc.l %0,%1" :: "r"(addr), "r"(PAGE_SHIFT << 2) : "memory");
@@ -204,9 +204,12 @@
 static inline void
 flush_tlb_pgtables (struct mm_struct *mm, unsigned long start, unsigned long end)
 {
+	struct vm_area_struct vma;
+
 	if (rgn_index(start) != rgn_index(end))
 		printk("flush_tlb_pgtables: can't flush across regions!!\n");
-	flush_tlb_range(mm, ia64_thash(start), ia64_thash(end));
+	vma.vm_mm = mm;
+	flush_tlb_range(&vma, ia64_thash(start), ia64_thash(end));
 }
 
 /*
@@ -217,7 +220,7 @@
 /* Caches aren't brain-dead on the IA-64. */
 #define flush_cache_all()			do { } while (0)
 #define flush_cache_mm(mm)			do { } while (0)
-#define flush_cache_range(mm, start, end)	do { } while (0)
+#define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr)		do { } while (0)
 #define flush_page_to_ram(page)			do { } while (0)
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-m68k/ide.h linux/include/asm-m68k/ide.h
--- v2.5.2/linux/include/asm-m68k/ide.h	Mon Jun 11 19:15:27 2001
+++ linux/include/asm-m68k/ide.h	Tue Jan 15 11:27:47 2002
@@ -89,7 +89,19 @@
 		unsigned unit		: 1;	/* drive select number, 0 or 1 */
 		unsigned head		: 4;	/* always zeros here */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+		unsigned reserved456	: 3;
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned bit0		: 1;
+	} b;
+} control_t;
 
 static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
 			unsigned long flags, const char *device, void *dev_id)
diff -u --recursive --new-file v2.5.2/linux/include/asm-m68k/motorola_pgalloc.h linux/include/asm-m68k/motorola_pgalloc.h
--- v2.5.2/linux/include/asm-m68k/motorola_pgalloc.h	Mon Jun 11 19:15:27 2001
+++ linux/include/asm-m68k/motorola_pgalloc.h	Tue Jan 15 10:56:36 2002
@@ -241,10 +241,10 @@
 		__flush_tlb_one(addr);
 }
 
-static inline void flush_tlb_range(struct mm_struct *mm,
+static inline void flush_tlb_range(struct vm_area_struct *vma,
 				   unsigned long start, unsigned long end)
 {
-	if (mm == current->mm)
+	if (vma->vm_mm == current->mm)
 		__flush_tlb();
 }
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-m68k/pgalloc.h linux/include/asm-m68k/pgalloc.h
--- v2.5.2/linux/include/asm-m68k/pgalloc.h	Thu Oct 25 13:53:55 2001
+++ linux/include/asm-m68k/pgalloc.h	Tue Jan 15 10:56:36 2002
@@ -89,11 +89,11 @@
 		__flush_cache_030();
 }
 
-extern inline void flush_cache_range(struct mm_struct *mm,
+extern inline void flush_cache_range(struct vm_area_struct *vma,
 				     unsigned long start,
 				     unsigned long end)
 {
-	if (mm == current->mm)
+	if (vma->vm_mm == current->mm)
 	        __flush_cache_030();
 }
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-m68k/sun3_pgalloc.h linux/include/asm-m68k/sun3_pgalloc.h
--- v2.5.2/linux/include/asm-m68k/sun3_pgalloc.h	Mon Jun 11 19:15:27 2001
+++ linux/include/asm-m68k/sun3_pgalloc.h	Tue Jan 15 10:56:36 2002
@@ -216,9 +216,10 @@
 }
 /* Flush a range of pages from TLB. */
 
-static inline void flush_tlb_range (struct mm_struct *mm,
+static inline void flush_tlb_range (struct vm_area_struct *vma,
 		      unsigned long start, unsigned long end)
 {
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned char seg, oldctx;
 	
 	start &= ~SUN3_PMEG_MASK;
diff -u --recursive --new-file v2.5.2/linux/include/asm-mips/gfx.h linux/include/asm-mips/gfx.h
--- v2.5.2/linux/include/asm-mips/gfx.h	Sat May 13 08:31:25 2000
+++ linux/include/asm-mips/gfx.h	Tue Jan 15 10:56:36 2002
@@ -48,9 +48,9 @@
 
 #ifdef __KERNEL__
 /* umap.c */
-extern void remove_mapping (struct task_struct *, unsigned long, unsigned long);
+extern void remove_mapping (struct vm_area_struct *vma, struct task_struct *, unsigned long, unsigned long);
 extern void *vmalloc_uncached (unsigned long size);
-extern int vmap_page_range (unsigned long from, unsigned long size, unsigned long vaddr);
+extern int vmap_page_range (struct vm_area_struct *vma, unsigned long from, unsigned long size, unsigned long vaddr);
 #endif
 
 #endif /* _ASM_GFX_H */
diff -u --recursive --new-file v2.5.2/linux/include/asm-mips/ide.h linux/include/asm-mips/ide.h
--- v2.5.2/linux/include/asm-mips/ide.h	Sun Sep  9 10:43:01 2001
+++ linux/include/asm-mips/ide.h	Tue Jan 15 11:27:47 2002
@@ -92,6 +92,26 @@
 	} b;
 } select_t;
 
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+#ifdef __MIPSEB__
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+		unsigned reserved456	: 3;
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned bit0		: 1;
+#else
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+#endif
+	} b;
+} control_t;
+
 static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int,void *, struct pt_regs *),
 			unsigned long flags, const char *device, void *dev_id)
 {
diff -u --recursive --new-file v2.5.2/linux/include/asm-mips/pci.h linux/include/asm-mips/pci.h
--- v2.5.2/linux/include/asm-mips/pci.h	Fri Oct 12 15:35:54 2001
+++ linux/include/asm-mips/pci.h	Tue Jan 15 11:48:13 2002
@@ -114,6 +114,14 @@
 	/* Nothing to do */
 }
 
+/* pci_unmap_{page,single} is a nop so... */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
+#define pci_unmap_addr(PTR, ADDR_NAME)		(0)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)	do { } while (0)
+#define pci_unmap_len(PTR, LEN_NAME)		(0)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)	do { } while (0)
+
 /*
  * Map a set of buffers described by scatterlist in streaming
  * mode for DMA.  This is the scather-gather version of the
diff -u --recursive --new-file v2.5.2/linux/include/asm-mips/pgalloc.h linux/include/asm-mips/pgalloc.h
--- v2.5.2/linux/include/asm-mips/pgalloc.h	Mon Jul  2 13:56:40 2001
+++ linux/include/asm-mips/pgalloc.h	Tue Jan 15 10:56:36 2002
@@ -16,12 +16,12 @@
  *
  *  - flush_tlb_all() flushes all processes TLB entries
  *  - flush_tlb_mm(mm) flushes the specified mm context TLB entries
- *  - flush_tlb_page(mm, vmaddr) flushes a single page
- *  - flush_tlb_range(mm, start, end) flushes a range of pages
+ *  - flush_tlb_page(vma, vmaddr) flushes a single page
+ *  - flush_tlb_range(vma, start, end) flushes a range of pages
  */
 extern void flush_tlb_all(void);
 extern void flush_tlb_mm(struct mm_struct *mm);
-extern void flush_tlb_range(struct mm_struct *mm, unsigned long start,
+extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 			       unsigned long end);
 extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-mips/pgtable.h linux/include/asm-mips/pgtable.h
--- v2.5.2/linux/include/asm-mips/pgtable.h	Sun Sep  9 10:43:01 2001
+++ linux/include/asm-mips/pgtable.h	Tue Jan 15 10:56:36 2002
@@ -23,14 +23,14 @@
  *  - flush_cache_all() flushes entire cache
  *  - flush_cache_mm(mm) flushes the specified mm context's cache lines
  *  - flush_cache_page(mm, vmaddr) flushes a single page
- *  - flush_cache_range(mm, start, end) flushes a range of pages
+ *  - flush_cache_range(vma, start, end) flushes a range of pages
  *  - flush_page_to_ram(page) write back kernel page to ram
  *  - flush_icache_range(start, end) flush a range of instructions
  */
 extern void (*_flush_cache_all)(void);
 extern void (*___flush_cache_all)(void);
 extern void (*_flush_cache_mm)(struct mm_struct *mm);
-extern void (*_flush_cache_range)(struct mm_struct *mm, unsigned long start,
+extern void (*_flush_cache_range)(struct vm_area_struct *vma, unsigned long start,
 				 unsigned long end);
 extern void (*_flush_cache_page)(struct vm_area_struct *vma, unsigned long page);
 extern void (*_flush_cache_sigtramp)(unsigned long addr);
@@ -44,7 +44,7 @@
 #define flush_cache_all()		_flush_cache_all()
 #define __flush_cache_all()		___flush_cache_all()
 #define flush_cache_mm(mm)		_flush_cache_mm(mm)
-#define flush_cache_range(mm,start,end)	_flush_cache_range(mm,start,end)
+#define flush_cache_range(vma,start,end) _flush_cache_range(vma,start,end)
 #define flush_cache_page(vma,page)	_flush_cache_page(vma, page)
 #define flush_cache_sigtramp(addr)	_flush_cache_sigtramp(addr)
 #define flush_page_to_ram(page)		_flush_page_to_ram(page)
diff -u --recursive --new-file v2.5.2/linux/include/asm-mips/umap.h linux/include/asm-mips/umap.h
--- v2.5.2/linux/include/asm-mips/umap.h	Fri Jun 25 17:37:53 1999
+++ linux/include/asm-mips/umap.h	Tue Jan 15 10:56:36 2002
@@ -1,7 +1,7 @@
 #ifndef __MIPS_UMAP_H
 #define __MIPS_UMAP_H
 
-void remove_mapping (struct task_struct *task, unsigned long start,
+void remove_mapping (struct vm_area_struct *vma, struct task_struct *task, unsigned long start,
 unsigned long end);
 
 #endif 
diff -u --recursive --new-file v2.5.2/linux/include/asm-mips64/gfx.h linux/include/asm-mips64/gfx.h
--- v2.5.2/linux/include/asm-mips64/gfx.h	Sun Sep  9 10:43:02 2001
+++ linux/include/asm-mips64/gfx.h	Tue Jan 15 10:56:36 2002
@@ -47,9 +47,9 @@
 
 #ifdef __KERNEL__
 /* umap.c */
-extern void remove_mapping (struct task_struct *, unsigned long, unsigned long);
+extern void remove_mapping (struct vm_area_struct *vma, struct task_struct *, unsigned long, unsigned long);
 extern void *vmalloc_uncached (unsigned long size);
-extern int vmap_page_range (unsigned long from, unsigned long size, unsigned long vaddr);
+extern int vmap_page_range (struct vm_area_struct *vma, unsigned long from, unsigned long size, unsigned long vaddr);
 #endif
 
 #endif /* _ASM_GFX_H */
diff -u --recursive --new-file v2.5.2/linux/include/asm-mips64/ide.h linux/include/asm-mips64/ide.h
--- v2.5.2/linux/include/asm-mips64/ide.h	Sun Sep  9 10:43:02 2001
+++ linux/include/asm-mips64/ide.h	Tue Jan 15 11:27:47 2002
@@ -85,7 +85,19 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int,void *, struct pt_regs *),
 			unsigned long flags, const char *device, void *dev_id)
diff -u --recursive --new-file v2.5.2/linux/include/asm-mips64/pci.h linux/include/asm-mips64/pci.h
--- v2.5.2/linux/include/asm-mips64/pci.h	Fri Oct 12 15:35:54 2001
+++ linux/include/asm-mips64/pci.h	Tue Jan 15 11:48:13 2002
@@ -86,6 +86,20 @@
 extern void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg,
                             int nelems, int direction);
 
+/* pci_unmap_{single,page} is not a nop, thus... */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)	\
+	dma_addr_t ADDR_NAME;
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)		\
+	__u32 LEN_NAME;
+#define pci_unmap_addr(PTR, ADDR_NAME)			\
+	((PTR)->ADDR_NAME)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)		\
+	(((PTR)->ADDR_NAME) = (VAL))
+#define pci_unmap_len(PTR, LEN_NAME)			\
+	((PTR)->LEN_NAME)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)		\
+	(((PTR)->LEN_NAME) = (VAL))
+
 #else /* CONFIG_MAPPED_PCI_IO  */
 
 /*
@@ -123,6 +137,14 @@
 
 	/* Nothing to do */
 }
+
+/* pci_unmap_{page,single} is a nop so... */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
+#define pci_unmap_addr(PTR, ADDR_NAME)		(0)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)	do { } while (0)
+#define pci_unmap_len(PTR, LEN_NAME)		(0)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)	do { } while (0)
 
 /*
  * Map a set of buffers described by scatterlist in streaming
diff -u --recursive --new-file v2.5.2/linux/include/asm-mips64/pgalloc.h linux/include/asm-mips64/pgalloc.h
--- v2.5.2/linux/include/asm-mips64/pgalloc.h	Wed Jul  4 11:50:39 2001
+++ linux/include/asm-mips64/pgalloc.h	Tue Jan 15 10:56:36 2002
@@ -15,13 +15,13 @@
  *
  *  - flush_tlb_all() flushes all processes TLB entries
  *  - flush_tlb_mm(mm) flushes the specified mm context TLB entries
- *  - flush_tlb_page(mm, vmaddr) flushes a single page
- *  - flush_tlb_range(mm, start, end) flushes a range of pages
+ *  - flush_tlb_page(vma, vmaddr) flushes a single page
+ *  - flush_tlb_range(vma, start, end) flushes a range of pages
  *  - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
  */
 extern void (*_flush_tlb_all)(void);
 extern void (*_flush_tlb_mm)(struct mm_struct *mm);
-extern void (*_flush_tlb_range)(struct mm_struct *mm, unsigned long start,
+extern void (*_flush_tlb_range)(struct vm_area_struct *vma, unsigned long start,
 			       unsigned long end);
 extern void (*_flush_tlb_page)(struct vm_area_struct *vma, unsigned long page);
 
@@ -29,14 +29,14 @@
 
 #define flush_tlb_all()			_flush_tlb_all()
 #define flush_tlb_mm(mm)		_flush_tlb_mm(mm)
-#define flush_tlb_range(mm,vmaddr,end)	_flush_tlb_range(mm, vmaddr, end)
+#define flush_tlb_range(vma,vmaddr,end)	_flush_tlb_range(vma, vmaddr, end)
 #define flush_tlb_page(vma,page)	_flush_tlb_page(vma, page)
 
 #else /* CONFIG_SMP */
 
 extern void flush_tlb_all(void);
 extern void flush_tlb_mm(struct mm_struct *);
-extern void flush_tlb_range(struct mm_struct *, unsigned long, unsigned long);
+extern void flush_tlb_range(struct vm_area_struct *, unsigned long, unsigned long);
 extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
 
 #endif /* CONFIG_SMP */
diff -u --recursive --new-file v2.5.2/linux/include/asm-mips64/pgtable.h linux/include/asm-mips64/pgtable.h
--- v2.5.2/linux/include/asm-mips64/pgtable.h	Sun Sep  9 10:43:02 2001
+++ linux/include/asm-mips64/pgtable.h	Tue Jan 15 10:56:36 2002
@@ -24,11 +24,11 @@
  *  - flush_cache_all() flushes entire cache
  *  - flush_cache_mm(mm) flushes the specified mm context's cache lines
  *  - flush_cache_page(mm, vmaddr) flushes a single page
- *  - flush_cache_range(mm, start, end) flushes a range of pages
+ *  - flush_cache_range(vma, start, end) flushes a range of pages
  *  - flush_page_to_ram(page) write back kernel page to ram
  */
 extern void (*_flush_cache_mm)(struct mm_struct *mm);
-extern void (*_flush_cache_range)(struct mm_struct *mm, unsigned long start,
+extern void (*_flush_cache_range)(struct vm_area_struct *vma, unsigned long start,
                                  unsigned long end);
 extern void (*_flush_cache_page)(struct vm_area_struct *vma, unsigned long page);
 extern void (*_flush_page_to_ram)(struct page * page);
@@ -38,7 +38,7 @@
 
 #ifndef CONFIG_CPU_R10000
 #define flush_cache_mm(mm)		_flush_cache_mm(mm)
-#define flush_cache_range(mm,start,end)	_flush_cache_range(mm,start,end)
+#define flush_cache_range(vma,start,end) _flush_cache_range(vma,start,end)
 #define flush_cache_page(vma,page)	_flush_cache_page(vma, page)
 #define flush_page_to_ram(page)		_flush_page_to_ram(page)
 
@@ -62,7 +62,7 @@
  */
 extern void andes_flush_icache_page(unsigned long);
 #define flush_cache_mm(mm)		do { } while(0)
-#define flush_cache_range(mm,start,end)	do { } while(0)
+#define flush_cache_range(vma,start,end) do { } while(0)
 #define flush_cache_page(vma,page)	do { } while(0)
 #define flush_page_to_ram(page)		do { } while(0)
 #define flush_icache_range(start, end)	_flush_cache_l1()
diff -u --recursive --new-file v2.5.2/linux/include/asm-parisc/ide.h linux/include/asm-parisc/ide.h
--- v2.5.2/linux/include/asm-parisc/ide.h	Tue Dec  5 12:29:39 2000
+++ linux/include/asm-parisc/ide.h	Tue Jan 15 11:27:47 2002
@@ -90,7 +90,19 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 #define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
 #define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
diff -u --recursive --new-file v2.5.2/linux/include/asm-parisc/pci.h linux/include/asm-parisc/pci.h
--- v2.5.2/linux/include/asm-parisc/pci.h	Fri Oct 12 15:35:54 2001
+++ linux/include/asm-parisc/pci.h	Tue Jan 15 11:48:13 2002
@@ -172,6 +172,20 @@
 #define pci_map_sg(p, sg, n, d)		hppa_dma_ops->map_sg(p, sg, n, d)
 #define pci_unmap_sg(p, sg, n, d)	hppa_dma_ops->unmap_sg(p, sg, n, d)
 
+/* pci_unmap_{single,page} is not a nop, thus... */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)	\
+	dma_addr_t ADDR_NAME;
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)		\
+	__u32 LEN_NAME;
+#define pci_unmap_addr(PTR, ADDR_NAME)			\
+	((PTR)->ADDR_NAME)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)		\
+	(((PTR)->ADDR_NAME) = (VAL))
+#define pci_unmap_len(PTR, LEN_NAME)			\
+	((PTR)->LEN_NAME)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)		\
+	(((PTR)->LEN_NAME) = (VAL))
+
 /* For U2/Astro/Ike based platforms (which are fully I/O coherent)
 ** dma_sync is a NOP. Let's keep the performance path short here.
 */
diff -u --recursive --new-file v2.5.2/linux/include/asm-parisc/pgalloc.h linux/include/asm-parisc/pgalloc.h
--- v2.5.2/linux/include/asm-parisc/pgalloc.h	Mon Apr 23 15:28:07 2001
+++ linux/include/asm-parisc/pgalloc.h	Tue Jan 15 10:56:36 2002
@@ -90,7 +90,7 @@
 }
 #endif
 
-#define flush_cache_range(mm, start, end) do { \
+#define flush_cache_range(vma, start, end) do { \
                 __flush_dcache_range(start, (unsigned long)end - (unsigned long)start); \
                 __flush_icache_range(start, (unsigned long)end - (unsigned long)start); \
 } while(0)
@@ -197,10 +197,10 @@
 		
 }
 
-static inline void flush_tlb_range(struct mm_struct *mm,
+static inline void flush_tlb_range(struct vm_area_struct *vma,
 	unsigned long start, unsigned long end)
 {
-	__flush_tlb_range(mm->context, start, end - start);
+	__flush_tlb_range(vma->vm_mm->context, start, end - start);
 }
 
 /*
diff -u --recursive --new-file v2.5.2/linux/include/asm-parisc/pgtable.h linux/include/asm-parisc/pgtable.h
--- v2.5.2/linux/include/asm-parisc/pgtable.h	Sun Nov 11 10:20:21 2001
+++ linux/include/asm-parisc/pgtable.h	Tue Jan 15 10:56:36 2002
@@ -34,10 +34,10 @@
 #define cache_push(paddr, len) \
 	do { \
 		unsigned long vaddr = phys_to_virt(paddr); \
-		flush_cache_range(&init_mm, vaddr, vaddr + len); \
+		flush_cache_range(0, vaddr, vaddr + len); \
 	} while(0)
 #define cache_push_v(vaddr, len) \
-			flush_cache_range(&init_mm, vaddr, vaddr + len)
+			flush_cache_range(0, vaddr, vaddr + len)
 
 /*
  * kern_addr_valid(ADDR) tests if ADDR is pointing to valid kernel
diff -u --recursive --new-file v2.5.2/linux/include/asm-ppc/ide.h linux/include/asm-ppc/ide.h
--- v2.5.2/linux/include/asm-ppc/ide.h	Mon Oct  8 11:40:13 2001
+++ linux/include/asm-ppc/ide.h	Tue Jan 15 11:27:47 2002
@@ -129,6 +129,18 @@
 	} b;
 } select_t;
 
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+		unsigned reserved456	: 3;
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned bit0		: 1;
+	} b;
+} control_t;
+
 #if !defined(ide_request_irq)
 #define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
 #endif
diff -u --recursive --new-file v2.5.2/linux/include/asm-ppc/pci.h linux/include/asm-ppc/pci.h
--- v2.5.2/linux/include/asm-ppc/pci.h	Sun Oct 21 10:13:07 2001
+++ linux/include/asm-ppc/pci.h	Tue Jan 15 11:48:13 2002
@@ -102,6 +102,13 @@
 	/* nothing to do */
 }
 
+/* pci_unmap_{page,single} is a nop so... */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
+#define pci_unmap_addr(PTR, ADDR_NAME)		(0)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)	do { } while (0)
+#define pci_unmap_len(PTR, LEN_NAME)		(0)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)	do { } while (0)
 
 /*
  * pci_{map,unmap}_single_page maps a kernel page to a dma_addr_t. identical
diff -u --recursive --new-file v2.5.2/linux/include/asm-ppc/pgtable.h linux/include/asm-ppc/pgtable.h
--- v2.5.2/linux/include/asm-ppc/pgtable.h	Sun Nov 11 10:20:21 2001
+++ linux/include/asm-ppc/pgtable.h	Tue Jan 15 10:56:36 2002
@@ -18,7 +18,7 @@
 extern void local_flush_tlb_all(void);
 extern void local_flush_tlb_mm(struct mm_struct *mm);
 extern void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
-extern void local_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+extern void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 				  unsigned long end);
 #define update_mmu_cache(vma, addr, pte)	do { } while (0)
 
@@ -32,7 +32,7 @@
 static inline void local_flush_tlb_page(struct vm_area_struct *vma,
 				unsigned long vmaddr)
 	{ __tlbia(); }
-static inline void local_flush_tlb_range(struct mm_struct *mm,
+static inline void local_flush_tlb_range(struct vm_area_struct *vma,
 				unsigned long start, unsigned long end)
 	{ __tlbia(); }
 #define update_mmu_cache(vma, addr, pte)	do { } while (0)
@@ -43,7 +43,7 @@
 extern void local_flush_tlb_all(void);
 extern void local_flush_tlb_mm(struct mm_struct *mm);
 extern void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
-extern void local_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+extern void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 			    unsigned long end);
 
 /*
@@ -80,7 +80,7 @@
  */
 #define flush_cache_all()		do { } while (0)
 #define flush_cache_mm(mm)		do { } while (0)
-#define flush_cache_range(mm, a, b)	do { } while (0)
+#define flush_cache_range(vma, a, b)	do { } while (0)
 #define flush_cache_page(vma, p)	do { } while (0)
 #define flush_icache_page(vma, page)	do { } while (0)
 
diff -u --recursive --new-file v2.5.2/linux/include/asm-s390/ide.h linux/include/asm-s390/ide.h
--- v2.5.2/linux/include/asm-s390/ide.h	Fri May 12 11:41:44 2000
+++ linux/include/asm-s390/ide.h	Tue Jan 15 11:27:47 2002
@@ -26,7 +26,19 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 #define ide_request_irq(irq,hand,flg,dev,id)	do {} while (0)
 #define ide_free_irq(irq,dev_id)		do {} while (0)
diff -u --recursive --new-file v2.5.2/linux/include/asm-s390/pgalloc.h linux/include/asm-s390/pgalloc.h
--- v2.5.2/linux/include/asm-s390/pgalloc.h	Thu Oct 11 09:43:38 2001
+++ linux/include/asm-s390/pgalloc.h	Tue Jan 15 10:56:36 2002
@@ -156,7 +156,7 @@
  *    called only from vmalloc/vfree
  *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
  *  - flush_tlb_page(vma, vmaddr) flushes one page
- *  - flush_tlb_range(mm, start, end) flushes a range of pages
+ *  - flush_tlb_range(vma, start, end) flushes a range of pages
  *  - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
  */
 
@@ -196,7 +196,7 @@
 {
 	local_flush_tlb();
 }
-static inline void flush_tlb_range(struct mm_struct *mm,
+static inline void flush_tlb_range(struct vm_area_struct *vma,
 				   unsigned long start, unsigned long end)
 {
 	local_flush_tlb();
@@ -264,10 +264,10 @@
 {
 	__flush_tlb_mm(vma->vm_mm);
 }
-static inline void flush_tlb_range(struct mm_struct *mm,
+static inline void flush_tlb_range(struct vm_area_struct *vma,
 				   unsigned long start, unsigned long end)
 {
-	__flush_tlb_mm(mm); 
+	__flush_tlb_mm(vma->vm_mm); 
 }
 
 #endif
diff -u --recursive --new-file v2.5.2/linux/include/asm-s390/pgtable.h linux/include/asm-s390/pgtable.h
--- v2.5.2/linux/include/asm-s390/pgtable.h	Thu Oct 11 09:43:38 2001
+++ linux/include/asm-s390/pgtable.h	Tue Jan 15 10:56:36 2002
@@ -36,7 +36,7 @@
 /* Caches aren't brain-dead on S390. */
 #define flush_cache_all()                       do { } while (0)
 #define flush_cache_mm(mm)                      do { } while (0)
-#define flush_cache_range(mm, start, end)       do { } while (0)
+#define flush_cache_range(vma, start, end)      do { } while (0)
 #define flush_cache_page(vma, vmaddr)           do { } while (0)
 #define flush_page_to_ram(page)                 do { } while (0)
 #define flush_dcache_page(page)			do { } while (0)
diff -u --recursive --new-file v2.5.2/linux/include/asm-s390x/ide.h linux/include/asm-s390x/ide.h
--- v2.5.2/linux/include/asm-s390x/ide.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/ide.h	Tue Jan 15 11:27:47 2002
@@ -26,7 +26,19 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 #define ide_request_irq(irq,hand,flg,dev,id)	do {} while (0)
 #define ide_free_irq(irq,dev_id)		do {} while (0)
diff -u --recursive --new-file v2.5.2/linux/include/asm-s390x/pgalloc.h linux/include/asm-s390x/pgalloc.h
--- v2.5.2/linux/include/asm-s390x/pgalloc.h	Wed Jul 25 14:12:02 2001
+++ linux/include/asm-s390x/pgalloc.h	Tue Jan 15 10:56:36 2002
@@ -192,7 +192,7 @@
  *    called only from vmalloc/vfree
  *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
  *  - flush_tlb_page(vma, vmaddr) flushes one page
- *  - flush_tlb_range(mm, start, end) flushes a range of pages
+ *  - flush_tlb_range(vma, start, end) flushes a range of pages
  *  - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
  */
 
@@ -232,7 +232,7 @@
 {
 	local_flush_tlb();
 }
-static inline void flush_tlb_range(struct mm_struct *mm,
+static inline void flush_tlb_range(struct vm_area_struct *vma,
 				   unsigned long start, unsigned long end)
 {
 	local_flush_tlb();
@@ -291,10 +291,10 @@
 {
 	__flush_tlb_mm(vma->vm_mm);
 }
-static inline void flush_tlb_range(struct mm_struct *mm,
+static inline void flush_tlb_range(struct vm_area_struct *vma,
 				   unsigned long start, unsigned long end)
 {
-	__flush_tlb_mm(mm); 
+	__flush_tlb_mm(vma->vm_mm);
 }
 
 #endif
diff -u --recursive --new-file v2.5.2/linux/include/asm-s390x/pgtable.h linux/include/asm-s390x/pgtable.h
--- v2.5.2/linux/include/asm-s390x/pgtable.h	Thu Oct 11 09:43:38 2001
+++ linux/include/asm-s390x/pgtable.h	Tue Jan 15 10:56:36 2002
@@ -32,7 +32,7 @@
 /* Caches aren't brain-dead on S390. */
 #define flush_cache_all()                       do { } while (0)
 #define flush_cache_mm(mm)                      do { } while (0)
-#define flush_cache_range(mm, start, end)       do { } while (0)
+#define flush_cache_range(vma, start, end)      do { } while (0)
 #define flush_cache_page(vma, vmaddr)           do { } while (0)
 #define flush_page_to_ram(page)                 do { } while (0)
 #define flush_dcache_page(page)			do { } while (0)
diff -u --recursive --new-file v2.5.2/linux/include/asm-sh/ide.h linux/include/asm-sh/ide.h
--- v2.5.2/linux/include/asm-sh/ide.h	Sat Sep  8 12:29:09 2001
+++ linux/include/asm-sh/ide.h	Tue Jan 15 11:27:47 2002
@@ -116,7 +116,19 @@
 		unsigned lba		: 1;	/* using LBA instead of CHS */
 		unsigned bit7		: 1;	/* always 1 */
 	} b;
-	} select_t;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 #define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
 #define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
diff -u --recursive --new-file v2.5.2/linux/include/asm-sh/pci.h linux/include/asm-sh/pci.h
--- v2.5.2/linux/include/asm-sh/pci.h	Tue Dec 18 14:56:40 2001
+++ linux/include/asm-sh/pci.h	Tue Jan 15 11:48:13 2002
@@ -89,6 +89,31 @@
 	return virt_to_bus(ptr);
 }
 
+/* pci_unmap_{single,page} being a nop depends upon the
+ * configuration.
+ */
+#ifdef CONFIG_SH_PCIDMA_NONCOHERENT
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)	\
+	dma_addr_t ADDR_NAME;
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)		\
+	__u32 LEN_NAME;
+#define pci_unmap_addr(PTR, ADDR_NAME)			\
+	((PTR)->ADDR_NAME)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)		\
+	(((PTR)->ADDR_NAME) = (VAL))
+#define pci_unmap_len(PTR, LEN_NAME)			\
+	((PTR)->LEN_NAME)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)		\
+	(((PTR)->LEN_NAME) = (VAL))
+#else
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
+#define pci_unmap_addr(PTR, ADDR_NAME)		(0)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)	do { } while (0)
+#define pci_unmap_len(PTR, LEN_NAME)		(0)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)	do { } while (0)
+#endif
+
 /* Unmap a single streaming mode DMA translation.  The dma_addr and size
  * must match what was provided for in a previous pci_map_single call.  All
  * other usages are undefined.
diff -u --recursive --new-file v2.5.2/linux/include/asm-sh/pgalloc.h linux/include/asm-sh/pgalloc.h
--- v2.5.2/linux/include/asm-sh/pgalloc.h	Sat Sep  8 12:29:09 2001
+++ linux/include/asm-sh/pgalloc.h	Tue Jan 15 10:56:36 2002
@@ -78,14 +78,14 @@
  *  - flush_tlb_all() flushes all processes TLBs
  *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
  *  - flush_tlb_page(vma, vmaddr) flushes one page
- *  - flush_tlb_range(mm, start, end) flushes a range of pages
+ *  - flush_tlb_range(vma, start, end) flushes a range of pages
  *  - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
  */
 
 extern void flush_tlb(void);
 extern void flush_tlb_all(void);
 extern void flush_tlb_mm(struct mm_struct *mm);
-extern void flush_tlb_range(struct mm_struct *mm, unsigned long start,
+extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 			    unsigned long end);
 extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
 extern void __flush_tlb_page(unsigned long asid, unsigned long page);
diff -u --recursive --new-file v2.5.2/linux/include/asm-sh/pgtable.h linux/include/asm-sh/pgtable.h
--- v2.5.2/linux/include/asm-sh/pgtable.h	Sun Nov 11 10:20:21 2001
+++ linux/include/asm-sh/pgtable.h	Tue Jan 15 10:56:36 2002
@@ -23,7 +23,7 @@
  *  - flush_cache_all() flushes entire cache
  *  - flush_cache_mm(mm) flushes the specified mm context's cache lines
  *  - flush_cache_page(mm, vmaddr) flushes a single page
- *  - flush_cache_range(mm, start, end) flushes a range of pages
+ *  - flush_cache_range(vma, start, end) flushes a range of pages
  *
  *  - flush_dcache_page(pg) flushes(wback&invalidates) a page for dcache
  *  - flush_page_to_ram(page) write back kernel page to ram
@@ -35,7 +35,7 @@
  */
 #define flush_cache_all()			do { } while (0)
 #define flush_cache_mm(mm)			do { } while (0)
-#define flush_cache_range(mm, start, end)	do { } while (0)
+#define flush_cache_range(vma, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr)		do { } while (0)
 #define flush_page_to_ram(page)			do { } while (0)
 #define flush_dcache_page(page)			do { } while (0)
@@ -55,7 +55,7 @@
 
 extern void flush_cache_all(void);
 extern void flush_cache_mm(struct mm_struct *mm);
-extern void flush_cache_range(struct mm_struct *mm, unsigned long start,
+extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
 			      unsigned long end);
 extern void flush_cache_page(struct vm_area_struct *vma, unsigned long addr);
 extern void flush_dcache_page(struct page *pg);
diff -u --recursive --new-file v2.5.2/linux/include/asm-sparc/ide.h linux/include/asm-sparc/ide.h
--- v2.5.2/linux/include/asm-sparc/ide.h	Mon Jun 19 17:59:39 2000
+++ linux/include/asm-sparc/ide.h	Tue Jan 15 11:27:47 2002
@@ -84,6 +84,18 @@
 	} b;
 } select_t;
 
+typedef union {
+	unsigned int all		: 8;	/* all of the bits together */
+	struct {
+		unsigned int HOB	: 1;	/* 48-bit address ordering */
+		unsigned int reserved456: 3;
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned int SRST	: 1;	/* host soft reset bit */
+		unsigned int nIEN	: 1;	/* device INTRQ to host *
+		unsigned int bit0	: 1;
+	} b;
+} control_t;
+
 static __inline__ int ide_request_irq(unsigned int irq,
 				      void (*handler)(int, void *, struct pt_regs *),
 				      unsigned long flags, const char *name, void *devid)
diff -u --recursive --new-file v2.5.2/linux/include/asm-sparc/pci.h linux/include/asm-sparc/pci.h
--- v2.5.2/linux/include/asm-sparc/pci.h	Mon Jan 14 18:25:11 2002
+++ linux/include/asm-sparc/pci.h	Tue Jan 15 11:48:13 2002
@@ -64,6 +64,20 @@
  */
 extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction);
 
+/* pci_unmap_{single,page} is not a nop, thus... */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)	\
+	dma_addr_t ADDR_NAME;
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)		\
+	__u32 LEN_NAME;
+#define pci_unmap_addr(PTR, ADDR_NAME)			\
+	((PTR)->ADDR_NAME)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)		\
+	(((PTR)->ADDR_NAME) = (VAL))
+#define pci_unmap_len(PTR, LEN_NAME)			\
+	((PTR)->LEN_NAME)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)		\
+	(((PTR)->LEN_NAME) = (VAL))
+
 /* Map a set of buffers described by scatterlist in streaming
  * mode for DMA.  This is the scather-gather version of the
  * above pci_map_single interface.  Here the scatter gather list
diff -u --recursive --new-file v2.5.2/linux/include/asm-sparc/pgalloc.h linux/include/asm-sparc/pgalloc.h
--- v2.5.2/linux/include/asm-sparc/pgalloc.h	Sun Oct 21 10:36:54 2001
+++ linux/include/asm-sparc/pgalloc.h	Tue Jan 15 10:56:36 2002
@@ -1,4 +1,4 @@
-/* $Id: pgalloc.h,v 1.15 2001/10/18 09:06:37 davem Exp $ */
+/* $Id: pgalloc.h,v 1.16 2001/12/21 04:56:17 davem Exp $ */
 #ifndef _SPARC_PGALLOC_H
 #define _SPARC_PGALLOC_H
 
@@ -13,22 +13,22 @@
 #ifdef CONFIG_SMP
 BTFIXUPDEF_CALL(void, local_flush_cache_all, void)
 BTFIXUPDEF_CALL(void, local_flush_cache_mm, struct mm_struct *)
-BTFIXUPDEF_CALL(void, local_flush_cache_range, struct mm_struct *, unsigned long, unsigned long)
+BTFIXUPDEF_CALL(void, local_flush_cache_range, struct vm_area_struct *, unsigned long, unsigned long)
 BTFIXUPDEF_CALL(void, local_flush_cache_page, struct vm_area_struct *, unsigned long)
 
 #define local_flush_cache_all() BTFIXUP_CALL(local_flush_cache_all)()
 #define local_flush_cache_mm(mm) BTFIXUP_CALL(local_flush_cache_mm)(mm)
-#define local_flush_cache_range(mm,start,end) BTFIXUP_CALL(local_flush_cache_range)(mm,start,end)
+#define local_flush_cache_range(vma,start,end) BTFIXUP_CALL(local_flush_cache_range)(vma,start,end)
 #define local_flush_cache_page(vma,addr) BTFIXUP_CALL(local_flush_cache_page)(vma,addr)
 
 BTFIXUPDEF_CALL(void, local_flush_tlb_all, void)
 BTFIXUPDEF_CALL(void, local_flush_tlb_mm, struct mm_struct *)
-BTFIXUPDEF_CALL(void, local_flush_tlb_range, struct mm_struct *, unsigned long, unsigned long)
+BTFIXUPDEF_CALL(void, local_flush_tlb_range, struct vm_area_struct *, unsigned long, unsigned long)
 BTFIXUPDEF_CALL(void, local_flush_tlb_page, struct vm_area_struct *, unsigned long)
 
 #define local_flush_tlb_all() BTFIXUP_CALL(local_flush_tlb_all)()
 #define local_flush_tlb_mm(mm) BTFIXUP_CALL(local_flush_tlb_mm)(mm)
-#define local_flush_tlb_range(mm,start,end) BTFIXUP_CALL(local_flush_tlb_range)(mm,start,end)
+#define local_flush_tlb_range(vma,start,end) BTFIXUP_CALL(local_flush_tlb_range)(vma,start,end)
 #define local_flush_tlb_page(vma,addr) BTFIXUP_CALL(local_flush_tlb_page)(vma,addr)
 
 BTFIXUPDEF_CALL(void, local_flush_page_to_ram, unsigned long)
@@ -39,14 +39,14 @@
 
 extern void smp_flush_cache_all(void);
 extern void smp_flush_cache_mm(struct mm_struct *mm);
-extern void smp_flush_cache_range(struct mm_struct *mm,
+extern void smp_flush_cache_range(struct vm_area_struct *vma,
 				  unsigned long start,
 				  unsigned long end);
 extern void smp_flush_cache_page(struct vm_area_struct *vma, unsigned long page);
 
 extern void smp_flush_tlb_all(void);
 extern void smp_flush_tlb_mm(struct mm_struct *mm);
-extern void smp_flush_tlb_range(struct mm_struct *mm,
+extern void smp_flush_tlb_range(struct vm_area_struct *vma,
 				  unsigned long start,
 				  unsigned long end);
 extern void smp_flush_tlb_page(struct vm_area_struct *mm, unsigned long page);
@@ -56,18 +56,18 @@
 
 BTFIXUPDEF_CALL(void, flush_cache_all, void)
 BTFIXUPDEF_CALL(void, flush_cache_mm, struct mm_struct *)
-BTFIXUPDEF_CALL(void, flush_cache_range, struct mm_struct *, unsigned long, unsigned long)
+BTFIXUPDEF_CALL(void, flush_cache_range, struct vm_area_struct *, unsigned long, unsigned long)
 BTFIXUPDEF_CALL(void, flush_cache_page, struct vm_area_struct *, unsigned long)
 
 #define flush_cache_all() BTFIXUP_CALL(flush_cache_all)()
 #define flush_cache_mm(mm) BTFIXUP_CALL(flush_cache_mm)(mm)
-#define flush_cache_range(mm,start,end) BTFIXUP_CALL(flush_cache_range)(mm,start,end)
+#define flush_cache_range(vma,start,end) BTFIXUP_CALL(flush_cache_range)(vma,start,end)
 #define flush_cache_page(vma,addr) BTFIXUP_CALL(flush_cache_page)(vma,addr)
 #define flush_icache_range(start, end)		do { } while (0)
 
 BTFIXUPDEF_CALL(void, flush_tlb_all, void)
 BTFIXUPDEF_CALL(void, flush_tlb_mm, struct mm_struct *)
-BTFIXUPDEF_CALL(void, flush_tlb_range, struct mm_struct *, unsigned long, unsigned long)
+BTFIXUPDEF_CALL(void, flush_tlb_range, struct vm_area_struct *, unsigned long, unsigned long)
 BTFIXUPDEF_CALL(void, flush_tlb_page, struct vm_area_struct *, unsigned long)
 
 extern __inline__ void flush_tlb_pgtables(struct mm_struct *mm, unsigned long start, unsigned long end)
@@ -76,7 +76,7 @@
 
 #define flush_tlb_all() BTFIXUP_CALL(flush_tlb_all)()
 #define flush_tlb_mm(mm) BTFIXUP_CALL(flush_tlb_mm)(mm)
-#define flush_tlb_range(mm,start,end) BTFIXUP_CALL(flush_tlb_range)(mm,start,end)
+#define flush_tlb_range(vma,start,end) BTFIXUP_CALL(flush_tlb_range)(vma,start,end)
 #define flush_tlb_page(vma,addr) BTFIXUP_CALL(flush_tlb_page)(vma,addr)
 
 BTFIXUPDEF_CALL(void, __flush_page_to_ram, unsigned long)
diff -u --recursive --new-file v2.5.2/linux/include/asm-sparc/pgtable.h linux/include/asm-sparc/pgtable.h
--- v2.5.2/linux/include/asm-sparc/pgtable.h	Tue Nov 13 09:16:05 2001
+++ linux/include/asm-sparc/pgtable.h	Tue Jan 15 10:56:36 2002
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.109 2001/11/13 00:49:32 davem Exp $ */
+/* $Id: pgtable.h,v 1.110 2001/12/21 04:56:17 davem Exp $ */
 #ifndef _SPARC_PGTABLE_H
 #define _SPARC_PGTABLE_H
 
@@ -445,7 +445,7 @@
 #define kern_addr_valid(addr) \
 	(test_bit(__pa((unsigned long)(addr))>>20, sparc_valid_addr_bitmap))
 
-extern int io_remap_page_range(unsigned long from, unsigned long to,
+extern int io_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long to,
 			       unsigned long size, pgprot_t prot, int space);
 
 #include <asm-generic/pgtable.h>
diff -u --recursive --new-file v2.5.2/linux/include/asm-sparc64/ide.h linux/include/asm-sparc64/ide.h
--- v2.5.2/linux/include/asm-sparc64/ide.h	Mon Oct  1 09:19:56 2001
+++ linux/include/asm-sparc64/ide.h	Tue Jan 15 11:27:47 2002
@@ -80,6 +80,18 @@
 	} b;
 } select_t;
 
+typedef union {
+	unsigned int all		: 8;	/* all of the bits together */
+	struct {
+		unsigned int HOB	: 1;	/* 48-bit address ordering */
+		unsigned int reserved456: 3;
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned int SRST	: 1;	/* host soft reset bit */
+		unsigned int nIEN	: 1;	/* device INTRQ to host *
+		unsigned int bit0	: 1;
+	} b;
+} control_t;
+
 static __inline__ int ide_request_irq(unsigned int irq,
 				      void (*handler)(int, void *, struct pt_regs *),
 				      unsigned long flags, const char *name, void *devid)
diff -u --recursive --new-file v2.5.2/linux/include/asm-sparc64/pci.h linux/include/asm-sparc64/pci.h
--- v2.5.2/linux/include/asm-sparc64/pci.h	Tue Nov 13 09:16:05 2001
+++ linux/include/asm-sparc64/pci.h	Tue Jan 15 11:48:13 2002
@@ -77,6 +77,20 @@
 	pci_map_single(dev, (page_address(page) + (off)), size, dir)
 #define pci_unmap_page(dev,addr,sz,dir) pci_unmap_single(dev,addr,sz,dir)
 
+/* pci_unmap_{single,page} is not a nop, thus... */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)	\
+	dma_addr_t ADDR_NAME;
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)		\
+	__u32 LEN_NAME;
+#define pci_unmap_addr(PTR, ADDR_NAME)			\
+	((PTR)->ADDR_NAME)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)		\
+	(((PTR)->ADDR_NAME) = (VAL))
+#define pci_unmap_len(PTR, LEN_NAME)			\
+	((PTR)->LEN_NAME)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)		\
+	(((PTR)->LEN_NAME) = (VAL))
+
 /* Map a set of buffers described by scatterlist in streaming
  * mode for DMA.  This is the scather-gather version of the
  * above pci_map_single interface.  Here the scatter gather list
diff -u --recursive --new-file v2.5.2/linux/include/asm-sparc64/pgalloc.h linux/include/asm-sparc64/pgalloc.h
--- v2.5.2/linux/include/asm-sparc64/pgalloc.h	Tue Oct 30 15:08:11 2001
+++ linux/include/asm-sparc64/pgalloc.h	Tue Jan 15 10:56:36 2002
@@ -1,4 +1,4 @@
-/* $Id: pgalloc.h,v 1.29 2001/10/20 12:38:51 davem Exp $ */
+/* $Id: pgalloc.h,v 1.30 2001/12/21 04:56:17 davem Exp $ */
 #ifndef _SPARC64_PGALLOC_H
 #define _SPARC64_PGALLOC_H
 
@@ -15,8 +15,7 @@
 /* These are the same regardless of whether this is an SMP kernel or not. */
 #define flush_cache_mm(__mm) \
 	do { if ((__mm) == current->mm) flushw_user(); } while(0)
-#define flush_cache_range(mm, start, end) \
-	flush_cache_mm(mm)
+extern void flush_cache_range(struct vm_area_struct *, unsigned long, unsigned long);
 #define flush_cache_page(vma, page) \
 	flush_cache_mm((vma)->vm_mm)
 
@@ -35,8 +34,10 @@
 extern void flush_dcache_page_impl(struct page *page);
 #ifdef CONFIG_SMP
 extern void smp_flush_dcache_page_impl(struct page *page, int cpu);
+extern void flush_dcache_page_all(struct mm_struct *mm, struct page *page);
 #else
 #define smp_flush_dcache_page_impl(page,cpu) flush_dcache_page_impl(page)
+#define flush_dcache_page_all(mm,page) flush_dcache_page_impl(page)
 #endif
 
 extern void flush_dcache_page(struct page *page);
@@ -62,11 +63,11 @@
 	__flush_tlb_mm(CTX_HWBITS((__mm)->context), SECONDARY_CONTEXT); \
 } while(0)
 
-#define flush_tlb_range(__mm, start, end) \
-do { if(CTX_VALID((__mm)->context)) { \
+#define flush_tlb_range(__vma, start, end) \
+do { if(CTX_VALID((__vma)->vm_mm->context)) { \
 	unsigned long __start = (start)&PAGE_MASK; \
 	unsigned long __end = PAGE_ALIGN(end); \
-	__flush_tlb_range(CTX_HWBITS((__mm)->context), __start, \
+	__flush_tlb_range(CTX_HWBITS((__vma)->vm_mm->context), __start, \
 			  SECONDARY_CONTEXT, __end, PAGE_SIZE, \
 			  (__end - __start)); \
      } \
@@ -84,15 +85,15 @@
 extern void smp_flush_cache_all(void);
 extern void smp_flush_tlb_all(void);
 extern void smp_flush_tlb_mm(struct mm_struct *mm);
-extern void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+extern void smp_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 				unsigned long end);
 extern void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page);
 
 #define flush_cache_all()	smp_flush_cache_all()
 #define flush_tlb_all()		smp_flush_tlb_all()
 #define flush_tlb_mm(mm)	smp_flush_tlb_mm(mm)
-#define flush_tlb_range(mm, start, end) \
-	smp_flush_tlb_range(mm, start, end)
+#define flush_tlb_range(vma, start, end) \
+	smp_flush_tlb_range(vma, start, end)
 #define flush_tlb_page(vma, page) \
 	smp_flush_tlb_page((vma)->vm_mm, page)
 
@@ -122,9 +123,13 @@
 	vpte_base = (tlb_type == spitfire ?
 		     VPTE_BASE_SPITFIRE :
 		     VPTE_BASE_CHEETAH);
-	flush_tlb_range(mm,
-			vpte_base + (s >> (PAGE_SHIFT - 3)),
-			vpte_base + (e >> (PAGE_SHIFT - 3)));
+	{
+		struct vm_area_struct vma;
+		vma.vm_mm = mm;
+		flush_tlb_range(&vma,
+				vpte_base + (s >> (PAGE_SHIFT - 3)),
+				vpte_base + (e >> (PAGE_SHIFT - 3)));
+	}
 }
 #undef VPTE_BASE_SPITFIRE
 #undef VPTE_BASE_CHEETAH
diff -u --recursive --new-file v2.5.2/linux/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h
--- v2.5.2/linux/include/asm-sparc64/pgtable.h	Tue Nov 13 09:16:05 2001
+++ linux/include/asm-sparc64/pgtable.h	Tue Jan 15 10:56:36 2002
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.152 2001/11/12 09:43:39 davem Exp $
+/* $Id: pgtable.h,v 1.155 2001/12/21 04:56:17 davem Exp $
  * pgtable.h: SpitFire page table operations.
  *
  * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -19,6 +19,23 @@
 #include <asm/page.h>
 #include <asm/processor.h>
 
+/* The kernel image occupies 0x4000000 to 0x1000000 (4MB --> 16MB).
+ * The page copy blockops use 0x1000000 to 0x18000000 (16MB --> 24MB).
+ * The PROM resides in an area spanning 0xf0000000 to 0x100000000.
+ * The vmalloc area spans 0x140000000 to 0x200000000.
+ * There is a single static kernel PMD which maps from 0x0 to address
+ * 0x400000000.
+ */
+#define	TLBTEMP_BASE		0x0000000001000000
+#define MODULES_VADDR		0x0000000002000000
+#define MODULES_LEN		0x000000007e000000
+#define MODULES_END		0x0000000080000000
+#define VMALLOC_START		0x0000000140000000
+#define VMALLOC_VMADDR(x)	((unsigned long)(x))
+#define VMALLOC_END		0x0000000200000000
+#define LOW_OBP_ADDRESS		0x00000000f0000000
+#define HI_OBP_ADDRESS		0x0000000100000000
+
 /* XXX All of this needs to be rethought so we can take advantage
  * XXX cheetah's full 64-bit virtual address space, ie. no more hole
  * XXX in the middle like on spitfire. -DaveM
@@ -77,13 +94,6 @@
 				 (1) : (PTRS_PER_PGD)))
 #define FIRST_USER_PGD_NR	0
 
-/* NOTE: TLB miss handlers depend heavily upon where this is. */
-#define VMALLOC_START		0x0000000140000000UL
-#define VMALLOC_VMADDR(x)	((unsigned long)(x))
-#define VMALLOC_END		0x0000000200000000UL
-#define LOW_OBP_ADDRESS		0xf0000000UL
-#define HI_OBP_ADDRESS		0x100000000UL
-
 #define pte_ERROR(e)	__builtin_trap()
 #define pmd_ERROR(e)	__builtin_trap()
 #define pgd_ERROR(e)	__builtin_trap()
@@ -290,8 +300,6 @@
 #define swp_entry_to_pte(x)		((pte_t) { (x).val })
 
 extern unsigned long prom_virt_to_phys(unsigned long, int *);
-#define LOW_OBP_ADDRESS		0xf0000000UL
-#define HI_OBP_ADDRESS		0x100000000UL
 
 extern __inline__ unsigned long
 sun4u_get_pte (unsigned long addr)
@@ -328,7 +336,7 @@
 #define kern_addr_valid(addr)	\
 	(test_bit(__pa((unsigned long)(addr))>>22, sparc64_valid_addr_bitmap))
 
-extern int io_remap_page_range(unsigned long from, unsigned long offset,
+extern int io_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long offset,
 			       unsigned long size, pgprot_t prot, int space);
 
 #include <asm-generic/pgtable.h>
diff -u --recursive --new-file v2.5.2/linux/include/linux/blk.h linux/include/linux/blk.h
--- v2.5.2/linux/include/linux/blk.h	Mon Jan 14 18:25:11 2002
+++ linux/include/linux/blk.h	Sat Jan 19 14:30:41 2002
@@ -90,9 +90,9 @@
 
 #define _elv_add_request(q, rq, back, p) do {				      \
 	if ((back))							      \
-		_elv_add_request_core((q), (rq), (q)->queue_head.prev, (p)); \
+		_elv_add_request_core((q), (rq), (q)->queue_head.prev, (p));  \
 	else								      \
-		_elv_add_request_core((q), (rq), &(q)->queue_head, 0);	      \
+		_elv_add_request_core((q), (rq), &(q)->queue_head, (p));      \
 } while (0)
 
 #define elv_add_request(q, rq, back) _elv_add_request((q), (rq), (back), 1)
diff -u --recursive --new-file v2.5.2/linux/include/linux/blkdev.h linux/include/linux/blkdev.h
--- v2.5.2/linux/include/linux/blkdev.h	Mon Jan 14 18:25:11 2002
+++ linux/include/linux/blkdev.h	Sat Jan 19 14:30:25 2002
@@ -80,6 +80,7 @@
  	*/
 	__REQ_DRIVE_CMD,
 	__REQ_DRIVE_TASK,
+	__REQ_DRIVE_ACB,
 
 	__REQ_PC,	/* packet command (special) */
 	__REQ_BLOCK_PC,	/* queued down pc from block layer */
@@ -99,10 +100,13 @@
 #define REQ_DONTPREP	(1 << __REQ_DONTPREP)
 #define REQ_DRIVE_CMD	(1 << __REQ_DRIVE_CMD)
 #define REQ_DRIVE_TASK	(1 << __REQ_DRIVE_TASK)
+#define REQ_DRIVE_ACB	(1 << __REQ_DRIVE_ACB)
 #define REQ_PC		(1 << __REQ_PC)
 #define REQ_SENSE	(1 << __REQ_SENSE)
 #define REQ_BLOCK_PC	(1 << __REQ_BLOCK_PC)
 #define REQ_SPECIAL	(1 << __REQ_SPECIAL)
+
+#define REQ_DRIVE_TASKFILE	REQ_DRIVE_ACB
 
 #include <linux/elevator.h>
 
diff -u --recursive --new-file v2.5.2/linux/include/linux/cciss_ioctl.h linux/include/linux/cciss_ioctl.h
--- v2.5.2/linux/include/linux/cciss_ioctl.h	Tue May  1 16:05:00 2001
+++ linux/include/linux/cciss_ioctl.h	Fri Jan 18 14:05:55 2002
@@ -184,6 +184,11 @@
 #define CCISS_GETDRIVVER   _IOR(CCISS_IOC_MAGIC, 9, DriverVer_type)
 #define CCISS_REVALIDVOLS  _IO(CCISS_IOC_MAGIC, 10)
 #define CCISS_PASSTHRU	   _IOWR(CCISS_IOC_MAGIC, 11, IOCTL_Command_struct)
+#define CCISS_DEREGDISK	   _IO(CCISS_IOC_MAGIC, 12)
 
+/* no longer used... use REGNEWD instead */ 
+#define CCISS_REGNEWDISK  _IOW(CCISS_IOC_MAGIC, 13, int)
+
+#define CCISS_REGNEWD	   _IO(CCISS_IOC_MAGIC, 14)
 
 #endif  
diff -u --recursive --new-file v2.5.2/linux/include/linux/file.h linux/include/linux/file.h
--- v2.5.2/linux/include/linux/file.h	Mon Jan 14 18:25:11 2002
+++ linux/include/linux/file.h	Sat Jan 19 14:29:58 2002
@@ -5,31 +5,40 @@
 #ifndef __LINUX_FILE_H
 #define __LINUX_FILE_H
 
-#include <linux/sched.h>
+#include <asm/atomic.h>
+#include <linux/posix_types.h>
+#include <linux/compiler.h>
+
+/*
+ * The default fd array needs to be at least BITS_PER_LONG,
+ * as this is the granularity returned by copy_fdset().
+ */
+#define NR_OPEN_DEFAULT BITS_PER_LONG
+
+/*
+ * Open file table structure
+ */
+struct files_struct {
+        atomic_t count;
+        rwlock_t file_lock;     /* Protects all the below members.  Nests inside tsk->alloc_lock */
+        int max_fds;
+        int max_fdset;
+        int next_fd;
+        struct file ** fd;      /* current fd array */
+        fd_set *close_on_exec;
+        fd_set *open_fds;
+        fd_set close_on_exec_init;
+        fd_set open_fds_init;
+        struct file * fd_array[NR_OPEN_DEFAULT];
+};
 
 extern void FASTCALL(fput(struct file *));
 extern struct file * FASTCALL(fget(unsigned int fd));
- 
-static inline int get_close_on_exec(unsigned int fd)
-{
-	struct files_struct *files = current->files;
-	int res;
-	read_lock(&files->file_lock);
-	res = FD_ISSET(fd, files->close_on_exec);
-	read_unlock(&files->file_lock);
-	return res;
-}
+extern void FASTCALL(set_close_on_exec(unsigned int fd, int flag));
+extern void put_filp(struct file *);
+extern int get_unused_fd(void);
+extern void FASTCALL(put_unused_fd(unsigned int fd));
 
-static inline void set_close_on_exec(unsigned int fd, int flag)
-{
-	struct files_struct *files = current->files;
-	write_lock(&files->file_lock);
-	if (flag)
-		FD_SET(fd, files->close_on_exec);
-	else
-		FD_CLR(fd, files->close_on_exec);
-	write_unlock(&files->file_lock);
-}
 
 static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd)
 {
@@ -43,60 +52,9 @@
 /*
  * Check whether the specified fd has an open file.
  */
-static inline struct file * fcheck(unsigned int fd)
-{
-	struct file * file = NULL;
-	struct files_struct *files = current->files;
-
-	if (fd < files->max_fds)
-		file = files->fd[fd];
-	return file;
-}
-
-extern void put_filp(struct file *);
-
-extern int get_unused_fd(void);
-
-static inline void __put_unused_fd(struct files_struct *files, unsigned int fd)
-{
-	FD_CLR(fd, files->open_fds);
-	if (fd < files->next_fd)
-		files->next_fd = fd;
-}
-
-static inline void put_unused_fd(unsigned int fd)
-{
-	struct files_struct *files = current->files;
-
-	write_lock(&files->file_lock);
-	__put_unused_fd(files, fd);
-	write_unlock(&files->file_lock);
-}
-
-/*
- * Install a file pointer in the fd array.  
- *
- * The VFS is full of places where we drop the files lock between
- * setting the open_fds bitmap and installing the file in the file
- * array.  At any such point, we are vulnerable to a dup2() race
- * installing a file in the array before us.  We need to detect this and
- * fput() the struct file we are about to overwrite in this case.
- *
- * It should never happen - if we allow dup2() do it, _really_ bad things
- * will follow.
- */
-
-static inline void fd_install(unsigned int fd, struct file * file)
-{
-	struct files_struct *files = current->files;
-	
-	write_lock(&files->file_lock);
-	if (files->fd[fd])
-		BUG();
-	files->fd[fd] = file;
-	write_unlock(&files->file_lock);
-}
+#define fcheck(fd)	fcheck_files(current->files, fd)
 
-void put_files_struct(struct files_struct *fs);
+extern void FASTCALL(fd_install(unsigned int fd, struct file * file));
+void FASTCALL(put_files_struct(struct files_struct *fs));
 
 #endif /* __LINUX_FILE_H */
diff -u --recursive --new-file v2.5.2/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.5.2/linux/include/linux/fs.h	Mon Jan 14 18:25:11 2002
+++ linux/include/linux/fs.h	Sat Jan 19 14:30:00 2002
@@ -262,7 +262,7 @@
 
 	wait_queue_head_t b_wait;
 
-	struct inode *	     b_inode;
+	int b_inode;				/* will go away */
 	struct list_head     b_inode_buffers;	/* doubly linked list of inode dirty buffers */
 };
 
@@ -859,6 +859,9 @@
  * without the big kernel lock held in all filesystems.
  */
 struct super_operations {
+   	struct inode *(*alloc_inode)(struct super_block *sb);
+	void (*destroy_inode)(struct inode *);
+
 	void (*read_inode) (struct inode *);
   
   	/* reiserfs kludge.  reiserfs needs 64 bits of information to
@@ -1151,7 +1154,16 @@
 extern void FASTCALL(__mark_dirty(struct buffer_head *bh));
 extern void FASTCALL(__mark_buffer_dirty(struct buffer_head *bh));
 extern void FASTCALL(mark_buffer_dirty(struct buffer_head *bh));
-extern void FASTCALL(buffer_insert_inode_data_queue(struct buffer_head *, struct inode *));
+extern void FASTCALL(buffer_insert_list(struct buffer_head *, struct list_head *));
+
+static inline void buffer_insert_inode_queue(struct buffer_head *bh, struct inode *inode)
+{
+	buffer_insert_list(bh, &inode->i_dirty_buffers);
+}
+static inline void buffer_insert_inode_data_queue(struct buffer_head *bh, struct inode *inode)
+{
+	buffer_insert_list(bh, &inode->i_dirty_data_buffers);
+}
 
 #define atomic_set_buffer_dirty(bh) test_and_set_bit(BH_Dirty, &(bh)->b_state)
 
@@ -1219,10 +1231,16 @@
 extern int fsync_super(struct super_block *);
 extern int fsync_no_super(struct block_device *);
 extern void sync_inodes_sb(struct super_block *);
-extern int osync_inode_buffers(struct inode *);
-extern int osync_inode_data_buffers(struct inode *);
-extern int fsync_inode_buffers(struct inode *);
-extern int fsync_inode_data_buffers(struct inode *);
+extern int osync_buffers_list(struct list_head *);
+extern int fsync_buffers_list(struct list_head *);
+static inline int fsync_inode_buffers(struct inode *inode)
+{
+	return fsync_buffers_list(&inode->i_dirty_buffers);
+}
+static inline int fsync_inode_data_buffers(struct inode *inode)
+{
+	return fsync_buffers_list(&inode->i_dirty_data_buffers);
+}
 extern int inode_has_buffers(struct inode *);
 extern void filemap_fdatasync(struct address_space *);
 extern void filemap_fdatawait(struct address_space *);
@@ -1327,6 +1345,7 @@
 #define user_path_walk(name,nd)	 __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd)
 #define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd)
 
+extern void inode_init_once(struct inode *);
 extern void iput(struct inode *);
 extern void force_delete(struct inode *);
 extern struct inode * igrab(struct inode *);
@@ -1340,20 +1359,8 @@
 }
 
 extern void clear_inode(struct inode *);
-extern struct inode * get_empty_inode(void);
-
-static inline struct inode * new_inode(struct super_block *sb)
-{
-	struct inode *inode = get_empty_inode();
-	if (inode) {
-		inode->i_sb = sb;
-		inode->i_dev = sb->s_dev;
-		inode->i_blkbits = sb->s_blocksize_bits;
-	}
-	return inode;
-}
+extern struct inode *new_inode(struct super_block *);
 extern void remove_suid(struct inode *inode);
-
 extern void insert_inode_hash(struct inode *);
 extern void remove_inode_hash(struct inode *);
 extern struct file * get_empty_filp(void);
diff -u --recursive --new-file v2.5.2/linux/include/linux/hdreg.h linux/include/linux/hdreg.h
--- v2.5.2/linux/include/linux/hdreg.h	Thu Nov 22 11:46:18 2001
+++ linux/include/linux/hdreg.h	Sat Jan 19 14:29:58 2002
@@ -6,104 +6,269 @@
  * Various sources.  
  */
 
-#define HD_IRQ 14		/* the standard disk interrupt */
+#define HD_IRQ 14			/* the standard disk interrupt */
 
 /* ide.c has its own port definitions in "ide.h" */
 
 /* Hd controller regs. Ref: IBM AT Bios-listing */
-#define HD_DATA		0x1f0	/* _CTL when writing */
-#define HD_ERROR	0x1f1	/* see err-bits */
-#define HD_NSECTOR	0x1f2	/* nr of sectors to read/write */
-#define HD_SECTOR	0x1f3	/* starting sector */
-#define HD_LCYL		0x1f4	/* starting cylinder */
-#define HD_HCYL		0x1f5	/* high byte of starting cyl */
-#define HD_CURRENT	0x1f6	/* 101dhhhh , d=drive, hhhh=head */
-#define HD_STATUS	0x1f7	/* see status-bits */
-#define HD_FEATURE HD_ERROR	/* same io address, read=error, write=feature */
-#define HD_PRECOMP HD_FEATURE	/* obsolete use of this port - predates IDE */
-#define HD_COMMAND HD_STATUS	/* same io address, read=status, write=cmd */
+#define HD_DATA		0x1f0		/* _CTL when writing */
+#define HD_ERROR	0x1f1		/* see err-bits */
+#define HD_NSECTOR	0x1f2		/* nr of sectors to read/write */
+#define HD_SECTOR	0x1f3		/* starting sector */
+#define HD_LCYL		0x1f4		/* starting cylinder */
+#define HD_HCYL		0x1f5		/* high byte of starting cyl */
+#define HD_CURRENT	0x1f6		/* 101dhhhh , d=drive, hhhh=head */
+#define HD_STATUS	0x1f7		/* see status-bits */
+#define HD_FEATURE	HD_ERROR	/* same io address, read=error, write=feature */
+#define HD_PRECOMP	HD_FEATURE	/* obsolete use of this port - predates IDE */
+#define HD_COMMAND	HD_STATUS	/* same io address, read=status, write=cmd */
 
-#define HD_CMD		0x3f6	/* used for resets */
-#define HD_ALTSTATUS	0x3f6	/* same as HD_STATUS but doesn't clear irq */
+#define HD_CMD		0x3f6		/* used for resets */
+#define HD_ALTSTATUS	0x3f6		/* same as HD_STATUS but doesn't clear irq */
 
 /* remainder is shared between hd.c, ide.c, ide-cd.c, and the hdparm utility */
 
 /* Bits of HD_STATUS */
-#define ERR_STAT	0x01
-#define INDEX_STAT	0x02
-#define ECC_STAT	0x04	/* Corrected error */
-#define DRQ_STAT	0x08
-#define SEEK_STAT	0x10
-#define WRERR_STAT	0x20
-#define READY_STAT	0x40
-#define BUSY_STAT	0x80
-
-/* Values for HD_COMMAND */
-#define WIN_RESTORE		0x10
-#define WIN_READ		0x20
-#define WIN_WRITE		0x30
-#define WIN_WRITE_VERIFY	0x3C
-#define WIN_VERIFY		0x40
-#define WIN_FORMAT		0x50
-#define WIN_INIT		0x60
-#define WIN_SEEK		0x70
-#define WIN_DIAGNOSE		0x90
-#define WIN_SPECIFY		0x91	/* set drive geometry translation */
-#define WIN_IDLEIMMEDIATE	0xE1	/* force drive to become "ready" */
-#define WIN_SETIDLE1		0xE3
-#define WIN_SETIDLE2		0x97
-
-#define WIN_STANDBYNOW1		0xE0
-#define WIN_STANDBYNOW2		0x94
-#define WIN_SLEEPNOW1		0xE6
-#define WIN_SLEEPNOW2		0x99
-#define WIN_CHECKPOWERMODE1	0xE5
-#define WIN_CHECKPOWERMODE2	0x98
-
-#define WIN_DOORLOCK		0xDE	/* lock door on removable drives */
-#define WIN_DOORUNLOCK		0xDF	/* unlock door on removable drives */
-
-#define WIN_MULTREAD		0xC4	/* read sectors using multiple mode */
-#define WIN_MULTWRITE		0xC5	/* write sectors using multiple mode */
-#define WIN_SETMULT		0xC6	/* enable/disable multiple mode */
-#define WIN_IDENTIFY		0xEC	/* ask drive to identify itself	*/
-#define WIN_IDENTIFY_DMA	0xEE	/* same as WIN_IDENTIFY, but DMA */
-#define WIN_SETFEATURES		0xEF	/* set special drive features */
-#define WIN_READDMA		0xC8	/* read sectors using DMA transfers */
-#define WIN_WRITEDMA		0xCA	/* write sectors using DMA transfers */
-
-#define WIN_QUEUED_SERVICE	0xA2	/* */
-#define WIN_READDMA_QUEUED	0xC7	/* read sectors using Queued DMA transfers */
-#define WIN_WRITEDMA_QUEUED	0xCC	/* write sectors using Queued DMA transfers */
-
-#define WIN_READ_BUFFER		0xE4	/* force read only 1 sector */
-#define WIN_WRITE_BUFFER	0xE8	/* force write only 1 sector */
-
-#define WIN_SMART		0xB0	/* self-monitoring and reporting */
-
-/* Additional drive command codes used by ATAPI devices. */
-#define WIN_PIDENTIFY		0xA1	/* identify ATAPI device	*/
-#define WIN_SRST		0x08	/* ATAPI soft reset command */
-#define WIN_PACKETCMD		0xA0	/* Send a packet command. */
+#define ERR_STAT		0x01
+#define INDEX_STAT		0x02
+#define ECC_STAT		0x04	/* Corrected error */
+#define DRQ_STAT		0x08
+#define SEEK_STAT		0x10
+#define WRERR_STAT		0x20
+#define READY_STAT		0x40
+#define BUSY_STAT		0x80
 
-#define DISABLE_SEAGATE		0xFB
-#define EXABYTE_ENABLE_NEST	0xF0
+/* Bits for HD_ERROR */
+#define MARK_ERR		0x01	/* Bad address mark */
+#define TRK0_ERR		0x02	/* couldn't find track 0 */
+#define ABRT_ERR		0x04	/* Command aborted */
+#define MCR_ERR			0x08	/* media change request */
+#define ID_ERR			0x10	/* ID field not found */
+#define MC_ERR			0x20	/* media changed */
+#define ECC_ERR			0x40	/* Uncorrectable ECC error */
+#define BBD_ERR			0x80	/* pre-EIDE meaning:  block marked bad */
+#define ICRC_ERR		0x80	/* new meaning:  CRC error during transfer */
+
+/*
+ * Command Header sizes for IOCTL commands
+ *	HDIO_DRIVE_CMD, HDIO_DRIVE_TASK, and HDIO_DRIVE_TASKFILE
+ */
+
+#if 0
+#include <asm/hdreg.h>
+typedef ide_ioreg_t task_ioreg_t;
+#else
+typedef unsigned char task_ioreg_t;
+#endif
+
+#define HDIO_DRIVE_CMD_HDR_SIZE		4*sizeof(task_ioreg_t)
+#define HDIO_DRIVE_TASK_HDR_SIZE	8*sizeof(task_ioreg_t)
+#define HDIO_DRIVE_HOB_HDR_SIZE		8*sizeof(task_ioreg_t)
+
+#define IDE_DRIVE_TASK_INVALID		-1
+#define IDE_DRIVE_TASK_NO_DATA		0
+#define IDE_DRIVE_TASK_SET_XFER		1
+
+#define IDE_DRIVE_TASK_IN		2
+
+#define IDE_DRIVE_TASK_OUT		3
+#define IDE_DRIVE_TASK_RAW_WRITE	4
+
+struct hd_drive_cmd_hdr {
+	task_ioreg_t command;
+	task_ioreg_t sector_number;
+	task_ioreg_t feature;
+	task_ioreg_t sector_count;
+};
 
-/* WIN_SMART sub-commands */
+typedef struct hd_drive_task_hdr {
+	task_ioreg_t data;
+	task_ioreg_t feature;
+	task_ioreg_t sector_count;
+	task_ioreg_t sector_number;
+	task_ioreg_t low_cylinder;
+	task_ioreg_t high_cylinder;
+	task_ioreg_t device_head;
+	task_ioreg_t command;
+} task_struct_t;
+
+typedef struct hd_drive_hob_hdr {
+	task_ioreg_t data;
+	task_ioreg_t feature;
+	task_ioreg_t sector_count;
+	task_ioreg_t sector_number;
+	task_ioreg_t low_cylinder;
+	task_ioreg_t high_cylinder;
+	task_ioreg_t device_head;
+	task_ioreg_t control;
+} hob_struct_t;
+
+typedef union ide_reg_valid_s {
+	unsigned all				: 16;
+	struct {
+		unsigned data			: 1;
+		unsigned error_feature		: 1;
+		unsigned sector			: 1;
+		unsigned nsector		: 1;
+		unsigned lcyl			: 1;
+		unsigned hcyl			: 1;
+		unsigned select			: 1;
+		unsigned status_command		: 1;
+
+		unsigned data_hob		: 1;
+		unsigned error_feature_hob	: 1;
+		unsigned sector_hob		: 1;
+		unsigned nsector_hob		: 1;
+		unsigned lcyl_hob		: 1;
+		unsigned hcyl_hob		: 1;
+		unsigned select_hob		: 1;
+		unsigned control_hob		: 1;
+	} b;
+} ide_reg_valid_t;
+
+/*
+ * Define standard taskfile in/out register
+ */
+#define IDE_TASKFILE_STD_OUT_FLAGS	0xFE
+#define IDE_TASKFILE_STD_IN_FLAGS	0xFE
+#define IDE_HOB_STD_OUT_FLAGS		0xC0
+#define IDE_HOB_STD_IN_FLAGS		0xC0
+
+typedef struct ide_task_request_s {
+	task_ioreg_t	io_ports[8];
+	task_ioreg_t	hob_ports[8];
+	ide_reg_valid_t	out_flags;
+	ide_reg_valid_t	in_flags;
+	int		data_phase;
+	int		req_cmd;
+	unsigned long	out_size;
+	unsigned long	in_size;
+} ide_task_request_t;
+
+typedef struct ide_ioctl_request_s {
+	ide_task_request_t	*task_request;
+	unsigned char		*out_buffer;
+	unsigned char		*in_buffer;
+} ide_ioctl_request_t;
+
+#define TASKFILE_INVALID		0x7fff
+#define TASKFILE_48			0x8000
+
+#define TASKFILE_NO_DATA		0x0000
+
+#define TASKFILE_IN			0x0001
+#define TASKFILE_MULTI_IN		0x0002
+
+#define TASKFILE_OUT			0x0004
+#define TASKFILE_MULTI_OUT		0x0008
+#define TASKFILE_IN_OUT			0x0010
+
+#define TASKFILE_IN_DMA			0x0020
+#define TASKFILE_OUT_DMA		0x0040
+#define TASKFILE_IN_DMAQ		0x0080
+#define TASKFILE_OUT_DMAQ		0x0100
+
+#define TASKFILE_P_IN			0x0200
+#define TASKFILE_P_OUT			0x0400
+#define TASKFILE_P_IN_DMA		0x0800
+#define TASKFILE_P_OUT_DMA		0x1000
+#define TASKFILE_P_IN_DMAQ		0x2000
+#define TASKFILE_P_OUT_DMAQ		0x4000
+
+/* ATA/ATAPI Commands pre T13 Spec */
+#define WIN_NOP				0x00
+#define CFA_REQ_EXT_ERROR_CODE		0x03 /* CFA Request Extended Error Code */
+#define WIN_SRST			0x08 /* ATAPI soft reset command */
+#define WIN_DEVICE_RESET		0x08
+#define WIN_RESTORE			0x10
+#define WIN_READ			0x20 /* 28-Bit */
+#define WIN_READ_EXT			0x24 /* 48-Bit */
+#define WIN_READDMA_EXT			0x25 /* 48-Bit */
+#define WIN_READDMA_QUEUED_EXT		0x26 /* 48-Bit */
+#define WIN_READ_NATIVE_MAX_EXT		0x27 /* 48-Bit */
+#define WIN_MULTREAD_EXT		0x29 /* 48-Bit */
+#define WIN_WRITE			0x30 /* 28-Bit */
+#define WIN_WRITE_EXT			0x34 /* 48-Bit */
+#define WIN_WRITEDMA_EXT		0x35 /* 48-Bit */
+#define WIN_WRITEDMA_QUEUED_EXT		0x36 /* 48-Bit */
+#define WIN_SET_MAX_EXT			0x37 /* 48-Bit */
+#define CFA_WRITE_SECT_WO_ERASE		0x38 /* CFA Write Sectors without erase */
+#define WIN_MULTWRITE_EXT		0x39 /* 48-Bit */
+#define WIN_WRITE_VERIFY		0x3C /* 28-Bit */
+#define WIN_VERIFY			0x40 /* 28-Bit - Read Verify Sectors */
+#define WIN_VERIFY_EXT			0x42 /* 48-Bit */
+#define WIN_FORMAT			0x50
+#define WIN_INIT			0x60
+#define WIN_SEEK			0x70
+#define CFA_TRANSLATE_SECTOR		0x87 /* CFA Translate Sector */
+#define WIN_DIAGNOSE			0x90
+#define WIN_SPECIFY			0x91 /* set drive geometry translation */
+#define WIN_DOWNLOAD_MICROCODE		0x92
+#define WIN_STANDBYNOW2			0x94
+#define WIN_SETIDLE2			0x97
+#define WIN_CHECKPOWERMODE2		0x98
+#define WIN_SLEEPNOW2			0x99
+#define WIN_PACKETCMD			0xA0 /* Send a packet command. */
+#define WIN_PIDENTIFY			0xA1 /* identify ATAPI device	*/
+#define WIN_QUEUED_SERVICE		0xA2
+#define WIN_SMART			0xB0 /* self-monitoring and reporting */
+#define CFA_ERASE_SECTORS       	0xC0
+#define WIN_MULTREAD			0xC4 /* read sectors using multiple mode*/
+#define WIN_MULTWRITE			0xC5 /* write sectors using multiple mode */
+#define WIN_SETMULT			0xC6 /* enable/disable multiple mode */
+#define WIN_READDMA_QUEUED		0xC7 /* read sectors using Queued DMA transfers */
+#define WIN_READDMA			0xC8 /* read sectors using DMA transfers */
+#define WIN_WRITEDMA			0xCA /* write sectors using DMA transfers */
+#define WIN_WRITEDMA_QUEUED		0xCC /* write sectors using Queued DMA transfers */
+#define CFA_WRITE_MULTI_WO_ERASE	0xCD /* CFA Write multiple without erase */
+#define WIN_GETMEDIASTATUS		0xDA	
+#define WIN_DOORLOCK			0xDE /* lock door on removable drives */
+#define WIN_DOORUNLOCK			0xDF /* unlock door on removable drives */
+#define WIN_STANDBYNOW1			0xE0
+#define WIN_IDLEIMMEDIATE		0xE1 /* force drive to become "ready" */
+#define WIN_STANDBY             	0xE2 /* Set device in Standby Mode */
+#define WIN_SETIDLE1			0xE3
+#define WIN_READ_BUFFER			0xE4 /* force read only 1 sector */
+#define WIN_CHECKPOWERMODE1		0xE5
+#define WIN_SLEEPNOW1			0xE6
+#define WIN_FLUSH_CACHE			0xE7
+#define WIN_WRITE_BUFFER		0xE8 /* force write only 1 sector */
+#define WIN_FLUSH_CACHE_EXT		0xEA /* 48-Bit */
+#define WIN_IDENTIFY			0xEC /* ask drive to identify itself	*/
+#define WIN_MEDIAEJECT			0xED
+#define WIN_IDENTIFY_DMA		0xEE /* same as WIN_IDENTIFY, but DMA */
+#define WIN_SETFEATURES			0xEF /* set special drive features */
+#define EXABYTE_ENABLE_NEST		0xF0
+#define WIN_SECURITY_SET_PASS		0xF1
+#define WIN_SECURITY_UNLOCK		0xF2
+#define WIN_SECURITY_ERASE_PREPARE	0xF3
+#define WIN_SECURITY_ERASE_UNIT		0xF4
+#define WIN_SECURITY_FREEZE_LOCK	0xF5
+#define WIN_SECURITY_DISABLE		0xF6
+#define WIN_READ_NATIVE_MAX		0xF8 /* return the native maximum address */
+#define WIN_SET_MAX			0xF9
+#define DISABLE_SEAGATE			0xFB
 
-#define SMART_READ_VALUES	0xd0
-#define SMART_READ_THRESHOLDS	0xd1
-#define SMART_AUTOSAVE		0xd2
-#define SMART_SAVE		0xd3
-#define SMART_IMMEDIATE_OFFLINE	0xd4
-#define SMART_READ_LOG_SECTOR	0xd5
-#define SMART_WRITE_LOG_SECTOR	0xd6
-#define SMART_WRITE_THRESHOLDS	0xd7
-#define SMART_ENABLE		0xd8
-#define SMART_DISABLE		0xd9
-#define SMART_STATUS		0xda
-#define SMART_AUTO_OFFLINE	0xdb
+/* WIN_SMART sub-commands */
 
+#define SMART_READ_VALUES		0xD0
+#define SMART_READ_THRESHOLDS		0xD1
+#define SMART_AUTOSAVE			0xD2
+#define SMART_SAVE			0xD3
+#define SMART_IMMEDIATE_OFFLINE		0xD4
+#define SMART_READ_LOG_SECTOR		0xD5
+#define SMART_WRITE_LOG_SECTOR		0xD6
+#define SMART_WRITE_THRESHOLDS		0xD7
+#define SMART_ENABLE			0xD8
+#define SMART_DISABLE			0xD9
+#define SMART_STATUS			0xDA
+#define SMART_AUTO_OFFLINE		0xDB
+
+/* Password used in TF4 & TF5 executing SMART commands */
+
+#define SMART_LCYL_PASS			0x4F
+#define SMART_HCYL_PASS			0xC2
+		
 /* WIN_SETFEATURES sub-commands */
 
 #define SETFEATURES_EN_WCACHE	0x02	/* Enable write cache */
@@ -131,6 +296,7 @@
 #define SETFEATURES_DIS_DEFECT	0x04	/* Disable Defect Management */
 #define SETFEATURES_EN_APM	0x05	/* Enable advanced power management */
 #define SETFEATURES_DIS_MSN	0x31	/* Disable Media Status Notification */
+#define SETFEATURES_EN_AAM	0x42	/* Enable Automatic Acoustic Management */
 #define SETFEATURES_DIS_RLA	0x55	/* Disable read look-ahead feature */
 #define SETFEATURES_EN_RI	0x5D	/* Enable release interrupt */
 #define SETFEATURES_EN_SI	0x5E	/* Enable SERVICE interrupt */
@@ -141,29 +307,19 @@
 #define SETFEATURES_EN_MSN	0x95	/* Enable Media Status Notification */
 #define SETFEATURES_EN_RLA	0xAA	/* Enable read look-ahead feature */
 #define SETFEATURES_PREFETCH	0xAB	/* Sets drive prefetch value */
+#define SETFEATURES_DIS_AAM	0xC2	/* Disable Automatic Acoustic Management */
 #define SETFEATURES_EN_RPOD	0xCC	/* Enable reverting to power on defaults */
 #define SETFEATURES_DIS_RI	0xDD	/* Disable release interrupt */
 #define SETFEATURES_DIS_SI	0xDE	/* Disable SERVICE interrupt */
 
 /* WIN_SECURITY sub-commands */
 
-#define SECURITY_SET_PASSWORD		0xBA	/* 0xF1 */
-#define SECURITY_UNLOCK			0xBB	/* 0xF2 */
-#define SECURITY_ERASE_PREPARE		0xBC	/* 0xF3 */
-#define SECURITY_ERASE_UNIT		0xBD	/* 0xF4 */
-#define SECURITY_FREEZE_LOCK		0xBE	/* 0xF5 */
-#define SECURITY_DISABLE_PASSWORD	0xBF	/* 0xF6 */
-
-/* Bits for HD_ERROR */
-#define MARK_ERR	0x01	/* Bad address mark */
-#define TRK0_ERR	0x02	/* couldn't find track 0 */
-#define ABRT_ERR	0x04	/* Command aborted */
-#define MCR_ERR		0x08	/* media change request */
-#define ID_ERR		0x10	/* ID field not found */
-#define MC_ERR		0x20	/* media changed */
-#define ECC_ERR		0x40	/* Uncorrectable ECC error */
-#define	BBD_ERR		0x80	/* pre-EIDE meaning:  block marked bad */
-#define	ICRC_ERR	0x80	/* new meaning:  CRC error during transfer */
+#define SECURITY_SET_PASSWORD		0xBA
+#define SECURITY_UNLOCK			0xBB
+#define SECURITY_ERASE_PREPARE		0xBC
+#define SECURITY_ERASE_UNIT		0xBD
+#define SECURITY_FREEZE_LOCK		0xBE
+#define SECURITY_DISABLE_PASSWORD	0xBF
 
 struct hd_geometry {
       unsigned char heads;
@@ -172,6 +328,14 @@
       unsigned long start;
 };
 
+/* BIG GEOMETRY */
+struct hd_big_geometry {
+	unsigned char heads;
+	unsigned char sectors;
+	unsigned int cylinders;
+	unsigned long start;
+};
+
 /* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x030n/0x031n */
 #define HDIO_GETGEO		0x0301	/* get device geometry */
 #define HDIO_GET_UNMASKINTR	0x0302	/* get current unmask setting */
@@ -186,9 +350,10 @@
 #define HDIO_GET_IDENTITY	0x030d	/* get IDE identification info */
 #define HDIO_GET_WCACHE		0x030e	/* get write cache mode on|off */
 #define HDIO_GET_ACOUSTIC	0x030f	/* get acoustic value */
+#define	HDIO_GET_ADDRESS	0x0310	/* */
 
 #define HDIO_GET_BUSSTATE	0x031a	/* get the bus state of the hwif */
-#define HDIO_TRISTATE_HWIF	0x031b	/* OBSOLETE - use SET_BUSSTATE */
+#define HDIO_TRISTATE_HWIF	0x031b	/* execute a channel tristate */
 #define HDIO_DRIVE_RESET	0x031c	/* execute a device reset */
 #define HDIO_DRIVE_TASKFILE	0x031d	/* execute raw taskfile */
 #define HDIO_DRIVE_TASK		0x031e	/* execute task and special drive command */
@@ -211,6 +376,7 @@
 #define HDIO_SET_ACOUSTIC	0x032c	/* change acoustic behavior */
 #define HDIO_SET_BUSSTATE	0x032d	/* set the bus state of the hwif */
 #define HDIO_SET_QDMA		0x032e	/* change use-qdma flag */
+#define HDIO_SET_ADDRESS	0x032f	/* change lba addressing modes */
 
 /* bus states */
 enum {
@@ -219,34 +385,30 @@
 	BUSSTATE_TRISTATE
 };
 
-/* BIG GEOMETRY */
-struct hd_big_geometry {
-	unsigned char heads;
-	unsigned char sectors;
-	unsigned int cylinders;
-	unsigned long start;
-};
-
 /* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x033n/0x033n */
 #define HDIO_GETGEO_BIG		0x0330	/* */
 #define HDIO_GETGEO_BIG_RAW	0x0331	/* */
 
 #define __NEW_HD_DRIVE_ID
-/* structure returned by HDIO_GET_IDENTITY, as per ANSI ATA2 rev.2f spec */
+/* structure returned by HDIO_GET_IDENTITY,
+ * as per ANSI NCITS ATA6 rev.1b spec
+ */
 struct hd_driveid {
 	unsigned short	config;		/* lots of obsolete bit flags */
-	unsigned short	cyls;		/* "physical" cyls */
+	unsigned short	cyls;		/* Obsolete, "physical" cyls */
 	unsigned short	reserved2;	/* reserved (word 2) */
-	unsigned short	heads;		/* "physical" heads */
+	unsigned short	heads;		/* Obsolete, "physical" heads */
 	unsigned short	track_bytes;	/* unformatted bytes per track */
 	unsigned short	sector_bytes;	/* unformatted bytes per sector */
-	unsigned short	sectors;	/* "physical" sectors per track */
+	unsigned short	sectors;	/* Obsolete, "physical" sectors per track */
 	unsigned short	vendor0;	/* vendor unique */
 	unsigned short	vendor1;	/* vendor unique */
-	unsigned short	vendor2;	/* vendor unique */
+	unsigned short	vendor2;	/* Retired vendor unique */
 	unsigned char	serial_no[20];	/* 0 = not_specified */
-	unsigned short	buf_type;
-	unsigned short	buf_size;	/* 512 byte increments; 0 = not_specified */
+	unsigned short	buf_type;	/* Retired */
+	unsigned short	buf_size;	/* Retired, 512 byte increments
+					 * 0 = not_specified
+					 */
 	unsigned short	ecc_bytes;	/* for r/w long cmds; 0 = not_specified */
 	unsigned char	fw_rev[8];	/* 0 = not_specified */
 	unsigned char	model[40];	/* 0 = not_specified */
@@ -254,72 +416,223 @@
 	unsigned char	vendor3;	/* vendor unique */
 	unsigned short	dword_io;	/* 0=not_implemented; 1=implemented */
 	unsigned char	vendor4;	/* vendor unique */
-	unsigned char	capability;	/* bits 0:DMA 1:LBA 2:IORDYsw 3:IORDYsup*/
+	unsigned char	capability;	/* (upper byte of word 49)
+					 *  3:	IORDYsup
+					 *  2:	IORDYsw
+					 *  1:	LBA
+					 *  0:	DMA
+					 */
 	unsigned short	reserved50;	/* reserved (word 50) */
-	unsigned char	vendor5;	/* vendor unique */
-	unsigned char	tPIO;		/* 0=slow, 1=medium, 2=fast */
-	unsigned char	vendor6;	/* vendor unique */
-	unsigned char	tDMA;		/* 0=slow, 1=medium, 2=fast */
-	unsigned short	field_valid;	/* bits 0:cur_ok 1:eide_ok */
-	unsigned short	cur_cyls;	/* logical cylinders */
-	unsigned short	cur_heads;	/* logical heads */
-	unsigned short	cur_sectors;	/* logical sectors per track */
-	unsigned short	cur_capacity0;	/* logical total sectors on drive */
-	unsigned short	cur_capacity1;	/*  (2 words, misaligned int)     */
+	unsigned char	vendor5;	/* Obsolete, vendor unique */
+	unsigned char	tPIO;		/* Obsolete, 0=slow, 1=medium, 2=fast */
+	unsigned char	vendor6;	/* Obsolete, vendor unique */
+	unsigned char	tDMA;		/* Obsolete, 0=slow, 1=medium, 2=fast */
+	unsigned short	field_valid;	/* (word 53)
+					 *  2:	ultra_ok	word  88
+					 *  1:	eide_ok		words 64-70
+					 *  0:	cur_ok		words 54-58
+					 */
+	unsigned short	cur_cyls;	/* Obsolete, logical cylinders */
+	unsigned short	cur_heads;	/* Obsolete, l heads */
+	unsigned short	cur_sectors;	/* Obsolete, l sectors per track */
+	unsigned short	cur_capacity0;	/* Obsolete, l total sectors on drive */
+	unsigned short	cur_capacity1;	/* Obsolete, (2 words, misaligned int)     */
 	unsigned char	multsect;	/* current multiple sector count */
 	unsigned char	multsect_valid;	/* when (bit0==1) multsect is ok */
-	unsigned int	lba_capacity;	/* total number of sectors */
-	unsigned short	dma_1word;	/* single-word dma info */
+	unsigned int	lba_capacity;	/* Obsolete, total number of sectors */
+	unsigned short	dma_1word;	/* Obsolete, single-word dma info */
 	unsigned short	dma_mword;	/* multiple-word dma info */
 	unsigned short  eide_pio_modes; /* bits 0:mode3 1:mode4 */
 	unsigned short  eide_dma_min;	/* min mword dma cycle time (ns) */
 	unsigned short  eide_dma_time;	/* recommended mword dma cycle time (ns) */
 	unsigned short  eide_pio;       /* min cycle time (ns), no IORDY  */
 	unsigned short  eide_pio_iordy; /* min cycle time (ns), with IORDY */
-	unsigned short	words69_70[2];	/* reserved words 69-70 */
+	unsigned short	words69_70[2];	/* reserved words 69-70
+					 * future command overlap and queuing
+					 */
 	/* HDIO_GET_IDENTITY currently returns only words 0 through 70 */
-	unsigned short	words71_74[4];	/* reserved words 71-74 */
-	unsigned short  queue_depth;	/*  */
+	unsigned short	words71_74[4];	/* reserved words 71-74
+					 * for IDENTIFY PACKET DEVICE command
+					 */
+	unsigned short  queue_depth;	/* (word 75)
+					 * 15:5	reserved
+					 *  4:0	Maximum queue depth -1
+					 */
 	unsigned short  words76_79[4];	/* reserved words 76-79 */
-	unsigned short  major_rev_num;	/*  */
-	unsigned short  minor_rev_num;	/*  */
-	unsigned short  command_set_1;	/* bits 0:Smart 1:Security 2:Removable 3:PM */
-	unsigned short  command_set_2;	/* bits 14:Smart Enabled 13:0 zero */
-	unsigned short  cfsse;		/* command set-feature supported extensions */
-	unsigned short  cfs_enable_1;	/* command set-feature enabled */
-	unsigned short  cfs_enable_2;	/* command set-feature enabled */
-	unsigned short  csf_default;	/* command set-feature default */
-	unsigned short  dma_ultra;	/*  */
+	unsigned short  major_rev_num;	/* (word 80) */
+	unsigned short  minor_rev_num;	/* (word 81) */
+	unsigned short  command_set_1;	/* (word 82) supported
+					 * 15:	Obsolete
+					 * 14:	NOP command
+					 * 13:	READ_BUFFER
+					 * 12:	WRITE_BUFFER
+					 * 11:	Obsolete
+					 * 10:	Host Protected Area
+					 *  9:	DEVICE Reset
+					 *  8:	SERVICE Interrupt
+					 *  7:	Release Interrupt
+					 *  6:	look-ahead
+					 *  5:	write cache
+					 *  4:	PACKET Command
+					 *  3:	Power Management Feature Set
+					 *  2:	Removable Feature Set
+					 *  1:	Security Feature Set
+					 *  0:	SMART Feature Set
+					 */
+	unsigned short  command_set_2;	/* (word 83)
+					 * 15:	Shall be ZERO
+					 * 14:	Shall be ONE
+					 * 13:	FLUSH CACHE EXT
+					 * 12:	FLUSH CACHE
+					 * 11:	Device Configuration Overlay
+					 * 10:	48-bit Address Feature Set
+					 *  9:	Automatic Acoustic Management
+					 *  8:	SET MAX security
+					 *  7:	reserved 1407DT PARTIES
+					 *  6:	SetF sub-command Power-Up
+					 *  5:	Power-Up in Standby Feature Set
+					 *  4:	Removable Media Notification
+					 *  3:	APM Feature Set
+					 *  2:	CFA Feature Set
+					 *  1:	READ/WRITE DMA QUEUED
+					 *  0:	Download MicroCode
+					 */
+	unsigned short  cfsse;		/* (word 84)
+					 * cmd set-feature supported extensions
+					 * 15:	Shall be ZERO
+					 * 14:	Shall be ONE
+					 * 13:3	reserved
+					 *  2:	Media Serial Number Valid
+					 *  1:	SMART selt-test supported
+					 *  0:	SMART error logging
+					 */
+	unsigned short  cfs_enable_1;	/* (word 85)
+					 * command set-feature enabled
+					 * 15:	Obsolete
+					 * 14:	NOP command
+					 * 13:	READ_BUFFER
+					 * 12:	WRITE_BUFFER
+					 * 11:	Obsolete
+					 * 10:	Host Protected Area
+					 *  9:	DEVICE Reset
+					 *  8:	SERVICE Interrupt
+					 *  7:	Release Interrupt
+					 *  6:	look-ahead
+					 *  5:	write cache
+					 *  4:	PACKET Command
+					 *  3:	Power Management Feature Set
+					 *  2:	Removable Feature Set
+					 *  1:	Security Feature Set
+					 *  0:	SMART Feature Set
+					 */
+	unsigned short  cfs_enable_2;	/* (word 86)
+					 * command set-feature enabled
+					 * 15:	Shall be ZERO
+					 * 14:	Shall be ONE
+					 * 13:	FLUSH CACHE EXT
+					 * 12:	FLUSH CACHE
+					 * 11:	Device Configuration Overlay
+					 * 10:	48-bit Address Feature Set
+					 *  9:	Automatic Acoustic Management
+					 *  8:	SET MAX security
+					 *  7:	reserved 1407DT PARTIES
+					 *  6:	SetF sub-command Power-Up
+					 *  5:	Power-Up in Standby Feature Set
+					 *  4:	Removable Media Notification
+					 *  3:	APM Feature Set
+					 *  2:	CFA Feature Set
+					 *  1:	READ/WRITE DMA QUEUED
+					 *  0:	Download MicroCode
+					 */
+	unsigned short  csf_default;	/* (word 87)
+					 * command set-feature default
+					 * 15:	Shall be ZERO
+					 * 14:	Shall be ONE
+					 * 13:3	reserved
+					 *  2:	Media Serial Number Valid
+					 *  1:	SMART selt-test supported
+					 *  0:	SMART error logging
+					 */
+	unsigned short  dma_ultra;	/* (word 88) */
 	unsigned short	word89;		/* reserved (word 89) */
 	unsigned short	word90;		/* reserved (word 90) */
 	unsigned short	CurAPMvalues;	/* current APM values */
 	unsigned short	word92;		/* reserved (word 92) */
-	unsigned short	hw_config;	/* hardware config */
-	unsigned short  words94_125[32];/* reserved words 94-125 */
-	unsigned short	last_lun;	/* reserved (word 126) */
-	unsigned short	word127;	/* reserved (word 127) */
-	unsigned short	dlf;		/* device lock function
+	unsigned short	hw_config;	/* hardware config (word 93)
+					 * 15:
+					 * 14:
+					 * 13:
+					 * 12:
+					 * 11:
+					 * 10:
+					 *  9:
+					 *  8:
+					 *  7:
+					 *  6:
+					 *  5:
+					 *  4:
+					 *  3:
+					 *  2:
+					 *  1:
+					 *  0:
+					 */
+	unsigned short	acoustic;	/* (word 94)
+					 * 15:8	Vendor's recommended value
+					 *  7:0	current value
+					 */
+	unsigned short	words95_99[5];	/* reserved words 95-99 */
+#if 0
+	unsigned short	words100_103[4]	;/* reserved words 100-103 */
+#else
+	unsigned long long lba_capacity_2;/* 48-bit total number of sectors */
+#endif
+	unsigned short	words104_125[22];/* reserved words 104-125 */
+	unsigned short	last_lun;	/* (word 126) */
+	unsigned short	word127;	/* (word 127) Feature Set
+					 * Removable Media Notification
+					 * 15:2	reserved
+					 *  1:0	00 = not supported
+					 *	01 = supported
+					 *	10 = reserved
+					 *	11 = reserved
+					 */
+	unsigned short	dlf;		/* (word 128)
+					 * device lock function
 					 * 15:9	reserved
-					 * 8	security level 1:max 0:high
-					 * 7:6	reserved
-					 * 5	enhanced erase
-					 * 4	expire
-					 * 3	frozen
-					 * 2	locked
-					 * 1	en/disabled
-					 * 0	capability
+					 *  8	security level 1:max 0:high
+					 *  7:6	reserved
+					 *  5	enhanced erase
+					 *  4	expire
+					 *  3	frozen
+					 *  2	locked
+					 *  1	en/disabled
+					 *  0	capability
 					 */
-	unsigned short  csfo;		/* current set features options
+	unsigned short  csfo;		/*  (word 129)
+					 * current set features options
 					 * 15:4	reserved
-					 * 3	auto reassign
-					 * 2	reverting
-					 * 1	read-look-ahead
-					 * 0	write cache
+					 *  3:	auto reassign
+					 *  2:	reverting
+					 *  1:	read-look-ahead
+					 *  0:	write cache
 					 */
 	unsigned short	words130_155[26];/* reserved vendor words 130-155 */
-	unsigned short	word156;
+	unsigned short	word156;	/* reserved vendor word 156 */
 	unsigned short	words157_159[3];/* reserved vendor words 157-159 */
-	unsigned short	words160_255[95];/* reserved words 160-255 */
+	unsigned short	cfa_power;	/* (word 160) CFA Power Mode
+					 * 15 word 160 supported
+					 * 14 reserved
+					 * 13
+					 * 12
+					 * 11:0
+					 */
+	unsigned short	words161_175[14];/* Reserved for CFA */
+	unsigned short	words176_205[31];/* Current Media Serial Number */
+	unsigned short	words206_254[48];/* reserved words 206-254 */
+	unsigned short	integrity_word;	/* (word 255)
+					 * 15:8 Checksum
+					 *  7:0 Signature
+					 */
 };
 
 /*
diff -u --recursive --new-file v2.5.2/linux/include/linux/highmem.h linux/include/linux/highmem.h
--- v2.5.2/linux/include/linux/highmem.h	Tue Dec 18 14:56:40 2001
+++ linux/include/linux/highmem.h	Sat Jan 19 14:30:22 2002
@@ -95,17 +95,6 @@
 	kunmap(page);
 }
 
-static inline void memclear_highpage(struct page *page, unsigned int offset, unsigned int size)
-{
-	char *kaddr;
-
-	if (offset + size > PAGE_SIZE)
-		BUG();
-	kaddr = kmap(page);
-	memset(kaddr + offset, 0, size);
-	kunmap(page);
-}
-
 /*
  * Same but also flushes aliased cache contents to RAM.
  */
@@ -117,6 +106,7 @@
 		BUG();
 	kaddr = kmap(page);
 	memset(kaddr + offset, 0, size);
+	flush_dcache_page(page);
 	flush_page_to_ram(page);
 	kunmap(page);
 }
@@ -130,17 +120,6 @@
 	copy_user_page(vto, vfrom, vaddr);
 	kunmap_atomic(vfrom, KM_USER0);
 	kunmap_atomic(vto, KM_USER1);
-}
-
-static inline void copy_highpage(struct page *to, struct page *from)
-{
-	char *vfrom, *vto;
-
-	vfrom = kmap(from);
-	vto = kmap(to);
-	copy_page(vto, vfrom);
-	kunmap(from);
-	kunmap(to);
 }
 
 #endif /* _LINUX_HIGHMEM_H */
diff -u --recursive --new-file v2.5.2/linux/include/linux/ide.h linux/include/linux/ide.h
--- v2.5.2/linux/include/linux/ide.h	Mon Jan 14 18:25:11 2002
+++ linux/include/linux/ide.h	Sat Jan 19 14:30:41 2002
@@ -65,13 +65,14 @@
 /*
  * IDE_DRIVE_CMD is used to implement many features of the hdparm utility
  */
-#define IDE_DRIVE_CMD		99	/* (magic) undef to reduce kernel size*/
+#define IDE_DRIVE_CMD			99	/* (magic) undef to reduce kernel size*/
+
+#define IDE_DRIVE_TASK			98
 
 /*
- * IDE_DRIVE_TASK is used to implement many features needed for raw tasks
+ * IDE_DRIVE_TASKFILE is used to implement many features needed for raw tasks
  */
-#define IDE_DRIVE_TASK		98
-#define IDE_DRIVE_CMD_AEB	98
+#define IDE_DRIVE_TASKFILE		97
 
 /*
  *  "No user-serviceable parts" beyond this point  :)
@@ -120,6 +121,17 @@
 #define IDE_FEATURE_OFFSET	IDE_ERROR_OFFSET
 #define IDE_COMMAND_OFFSET	IDE_STATUS_OFFSET
 
+#define IDE_DATA_OFFSET_HOB	(0)
+#define IDE_ERROR_OFFSET_HOB	(1)
+#define IDE_NSECTOR_OFFSET_HOB	(2)
+#define IDE_SECTOR_OFFSET_HOB	(3)
+#define IDE_LCYL_OFFSET_HOB	(4)
+#define IDE_HCYL_OFFSET_HOB	(5)
+#define IDE_SELECT_OFFSET_HOB	(6)
+#define IDE_CONTROL_OFFSET_HOB	(7)
+
+#define IDE_FEATURE_OFFSET_HOB	IDE_ERROR_OFFSET_HOB
+
 #define IDE_DATA_REG		(HWIF(drive)->io_ports[IDE_DATA_OFFSET])
 #define IDE_ERROR_REG		(HWIF(drive)->io_ports[IDE_ERROR_OFFSET])
 #define IDE_NSECTOR_REG		(HWIF(drive)->io_ports[IDE_NSECTOR_OFFSET])
@@ -131,6 +143,16 @@
 #define IDE_CONTROL_REG		(HWIF(drive)->io_ports[IDE_CONTROL_OFFSET])
 #define IDE_IRQ_REG		(HWIF(drive)->io_ports[IDE_IRQ_OFFSET])
 
+#define IDE_DATA_REG_HOB	(HWIF(drive)->io_ports[IDE_DATA_OFFSET])
+#define IDE_ERROR_REG_HOB	(HWIF(drive)->io_ports[IDE_ERROR_OFFSET])
+#define IDE_NSECTOR_REG_HOB	(HWIF(drive)->io_ports[IDE_NSECTOR_OFFSET])
+#define IDE_SECTOR_REG_HOB	(HWIF(drive)->io_ports[IDE_SECTOR_OFFSET])
+#define IDE_LCYL_REG_HOB	(HWIF(drive)->io_ports[IDE_LCYL_OFFSET])
+#define IDE_HCYL_REG_HOB	(HWIF(drive)->io_ports[IDE_HCYL_OFFSET])
+#define IDE_SELECT_REG_HOB	(HWIF(drive)->io_ports[IDE_SELECT_OFFSET])
+#define IDE_STATUS_REG_HOB	(HWIF(drive)->io_ports[IDE_STATUS_OFFSET])
+#define IDE_CONTROL_REG_HOB	(HWIF(drive)->io_ports[IDE_CONTROL_OFFSET])
+
 #define IDE_FEATURE_REG		IDE_ERROR_REG
 #define IDE_COMMAND_REG		IDE_STATUS_REG
 #define IDE_ALTSTATUS_REG	IDE_CONTROL_REG
@@ -171,11 +193,21 @@
 #define PARTN_BITS	6	/* number of minor dev bits for partitions */
 #define PARTN_MASK	((1<<PARTN_BITS)-1)	/* a useful bit mask */
 #define MAX_DRIVES	2	/* per interface; 2 assumed by lots of code */
-#define SECTOR_WORDS	(512 / 4)	/* number of 32bit words per sector */
+#define CASCADE_DRIVES	8	/* per interface; 8|2 assumed by lots of code */
+#define SECTOR_SIZE	512
+#define SECTOR_WORDS	(SECTOR_SIZE / 4)	/* number of 32bit words per sector */
 #define IDE_LARGE_SEEK(b1,b2,t)	(((b1) > (b2) + (t)) || ((b2) > (b1) + (t)))
 #define IDE_MIN(a,b)	((a)<(b) ? (a):(b))
 #define IDE_MAX(a,b)	((a)>(b) ? (a):(b))
 
+#ifndef SPLIT_WORD
+#  define SPLIT_WORD(W,HB,LB) ((HB)=(W>>8), (LB)=(W-((W>>8)<<8)))
+#endif
+#ifndef MAKE_WORD
+#  define MAKE_WORD(W,HB,LB) ((W)=((HB<<8)+LB))
+#endif
+
+
 /*
  * Timeouts for various operations:
  */
@@ -185,8 +217,7 @@
 #else
 #define WAIT_READY	(3*HZ/100)	/* 30msec - should be instantaneous */
 #endif /* CONFIG_APM || CONFIG_APM_MODULE */
-#define WAIT_PIDENTIFY	(10*HZ)	/* 10sec  - should be less than 3ms (?)
-				            if all ATAPI CD is closed at boot */
+#define WAIT_PIDENTIFY	(10*HZ)	/* 10sec  - should be less than 3ms (?), if all ATAPI CD is closed at boot */
 #define WAIT_WORSTCASE	(30*HZ)	/* 30sec  - worst case when spinning up */
 #define WAIT_CMD	(10*HZ)	/* 10sec  - maximum wait for an IRQ to happen */
 #define WAIT_MIN_SLEEP	(2*HZ/100)	/* 20msec - minimum sleep time */
@@ -224,6 +255,11 @@
 		(drive)->quirk_list = hwif->quirkproc(drive);	\
 }
 
+#define HOST(hwif,chipset)					\
+{								\
+	return ((hwif)->chipset == chipset) ? 1 : 0;		\
+}
+
 #define IDE_DEBUG(lineno) \
 	printk("%s,%s,line=%d\n", __FILE__, __FUNCTION__, (lineno))
 
@@ -249,11 +285,11 @@
                 ide_pmac,       ide_etrax100
 } hwif_chipset_t;
 
+
 #define IDE_CHIPSET_PCI_MASK    \
     ((1<<ide_pci)|(1<<ide_cmd646)|(1<<ide_ali14xx))
 #define IDE_CHIPSET_IS_PCI(c)   ((IDE_CHIPSET_PCI_MASK >> (c)) & 1)
 
-
 /*
  * Structure to hold all information about the location of this port
  */
@@ -292,16 +328,20 @@
 #ifndef HAVE_ARCH_OUT_BYTE
 #ifdef REALLY_FAST_IO
 #define OUT_BYTE(b,p)          outb((b),(p))
+#define OUT_WORD(w,p)          outw((w),(p))
 #else
 #define OUT_BYTE(b,p)          outb_p((b),(p))
+#define OUT_WORD(w,p)          outw_p((w),(p))
 #endif
 #endif
 
 #ifndef HAVE_ARCH_IN_BYTE
 #ifdef REALLY_FAST_IO
-#define IN_BYTE(p)             (byte)inb_p(p)
-#else
 #define IN_BYTE(p)             (byte)inb(p)
+#define IN_WORD(p)             (short)inw(p)
+#else
+#define IN_BYTE(p)             (byte)inb_p(p)
+#define IN_WORD(p)             (short)inw_p(p)
 #endif
 #endif
 
@@ -361,6 +401,7 @@
 	unsigned autotune	: 2;	/* 1=autotune, 2=noautotune, 0=default */
 	unsigned remap_0_to_1	: 2;	/* 0=remap if ezdrive, 1=remap, 2=noremap */
 	unsigned ata_flash	: 1;	/* 1=present, 0=default */
+	unsigned	addressing;	/* : 2; 0=28-bit, 1=48-bit, 2=64-bit */
 	byte		scsi;		/* 0=default, 1=skip current ide-subdriver for ide-scsi emulation */
 	byte		media;		/* disk, cdrom, tape, floppy, ... */
 	select_t	select;		/* basic drive/head select reg value */
@@ -373,7 +414,7 @@
 	byte		bad_wstat;	/* used for ignoring WRERR_STAT */
 	byte		nowerr;		/* used for ignoring WRERR_STAT */
 	byte		sect0;		/* offset of first sector for DM6:DDO */
-	byte 		usage;		/* current "open()" count for drive */
+	unsigned int	usage;		/* current "open()" count for drive */
 	byte 		head;		/* "real" number of heads */
 	byte		sect;		/* "real" sectors per track */
 	byte		bios_head;	/* BIOS/fdisk/LILO number of heads */
@@ -381,6 +422,7 @@
 	unsigned int	bios_cyl;	/* BIOS/fdisk/LILO number of cyls */
 	unsigned int	cyl;		/* "real" number of cyls */
 	unsigned long	capacity;	/* total number of sectors */
+	unsigned long long capacity48;	/* total number of sectors */
 	unsigned int	drive_data;	/* for use by tuneproc/selectproc as needed */
 	void		  *hwif;	/* actually (ide_hwif_t *) */
 	wait_queue_head_t wqueue;	/* used to wait for drive in open() */
@@ -402,6 +444,8 @@
 	byte		init_speed;	/* transfer rate set at boot */
 	byte		current_speed;	/* current transfer rate set */
 	byte		dn;		/* now wide spread use */
+	byte		wcache;		/* status of write cache */
+	byte		acoustic;	/* acoustic management */
 	unsigned int	failures;	/* current failure count */
 	unsigned int	max_failures;	/* maximum allowed failure count */
 } ide_drive_t;
@@ -471,7 +515,7 @@
 /*
  * ide soft-power support
  */
-typedef int (ide_busproc_t) (struct hwif_s *, int);
+typedef int (ide_busproc_t) (ide_drive_t *, int);
 
 #ifdef CONFIG_BLK_DEV_IDEPCI
 typedef struct ide_pci_devid_s {
@@ -538,7 +582,6 @@
 	byte		bus_state;	/* power state of the IDE bus */
 } ide_hwif_t;
 
-
 /*
  * Status returned from various ide_ functions
  */
@@ -550,7 +593,9 @@
 /*
  *  internal ide interrupt handler type
  */
+typedef ide_startstop_t (ide_pre_handler_t)(ide_drive_t *, struct request *);
 typedef ide_startstop_t (ide_handler_t)(ide_drive_t *);
+typedef ide_startstop_t (ide_post_handler_t)(ide_drive_t *);
 
 /*
  * when ide_timer_expiry fires, invoke a handler of this type
@@ -573,6 +618,8 @@
 	ide_expiry_t		*expiry;	/* queried upon timeouts */
 } ide_hwgroup_t;
 
+/* structure attached to the request for IDE_TASK_CMDS */
+
 /*
  * configurable drive settings
  */
@@ -623,6 +670,8 @@
 #ifdef CONFIG_PROC_FS
 void proc_ide_create(void);
 void proc_ide_destroy(void);
+void recreate_proc_ide_device(ide_hwif_t *, ide_drive_t *);
+void destroy_proc_ide_device(ide_hwif_t *, ide_drive_t *);
 void destroy_proc_ide_drives(ide_hwif_t *);
 void create_proc_ide_interfaces(void);
 void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data);
@@ -655,6 +704,8 @@
 #define IDE_SUBDRIVER_VERSION	1
 
 typedef int		(ide_cleanup_proc)(ide_drive_t *);
+typedef int		(ide_standby_proc)(ide_drive_t *);
+typedef int		(ide_flushcache_proc)(ide_drive_t *);
 typedef ide_startstop_t	(ide_do_request_proc)(ide_drive_t *, struct request *, unsigned long);
 typedef void		(ide_end_request_proc)(byte, ide_hwgroup_t *);
 typedef int		(ide_ioctl_proc)(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
@@ -676,6 +727,8 @@
 	unsigned supports_dma		: 1;
 	unsigned supports_dsc_overlap	: 1;
 	ide_cleanup_proc		*cleanup;
+	ide_standby_proc		*standby;
+	ide_flushcache_proc		*flushcache;
 	ide_do_request_proc		*do_request;
 	ide_end_request_proc		*end_request;
 	ide_ioctl_proc			*ioctl;
@@ -733,19 +786,7 @@
 inline int __ide_end_request(ide_hwgroup_t *, int, int);
 int ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup);
 
-/*
- * This is used for (nearly) all data transfers from/to the IDE interface
- * FIXME for 2.5, to a pointer pass verses memcpy........
- */
-void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
-void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
-
-/*
- * This is used for (nearly) all ATAPI data transfers from/to the IDE interface
- * FIXME for 2.5, to a pointer pass verses memcpy........
- */
-void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);
-void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);
+int drive_is_ready (ide_drive_t *drive);
 
 /*
  * This is used on exit from the driver, to designate the next irq handler
@@ -768,7 +809,7 @@
  * Issue a simple drive command
  * The drive must be selected beforehand.
  */
-void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler);
+void ide_cmd (ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler);
 
 /*
  * ide_fixstring() cleans up and (optionally) byte-swaps a text string,
@@ -843,6 +884,9 @@
  */
 #define ide_rq_offset(rq) (((rq)->hard_cur_sectors - (rq)->current_nr_sectors) << 9)
 
+#define task_rq_offset(rq) \
+	(((rq)->nr_sectors - (rq)->current_nr_sectors) * SECTOR_SIZE)
+
 extern inline void *ide_map_buffer(struct request *rq, unsigned long *flags)
 {
 	return bio_kmap_irq(rq->bio, flags) + ide_rq_offset(rq);
@@ -854,6 +898,24 @@
 }
 
 /*
+ * for now, taskfile requests are special :/
+ */
+extern inline char *ide_map_rq(struct request *rq, unsigned long *flags)
+{
+	if (rq->bio)
+		return ide_map_buffer(rq, flags);
+	else
+		return rq->buffer + task_rq_offset(rq);
+}
+
+extern inline void ide_unmap_rq(struct request *rq, char *buf,
+				unsigned long *flags)
+{
+	if (rq->bio)
+		ide_unmap_buffer(buf, flags);
+}
+
+/*
  * This function issues a special IDE device request
  * onto the request queue.
  *
@@ -883,24 +945,91 @@
 /*
  * Clean up after success/failure of an explicit drive cmd.
  * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_CMD).
+ * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASK_MASK).
  */
 void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err);
 
 /*
- * Issue ATA command and wait for completion.
+ * Issue ATA command and wait for completion. use for implementing commands in kernel
  */
 int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf);
+
 int ide_wait_cmd_task (ide_drive_t *drive, byte *buf);
+ 
+typedef struct ide_task_s {
+	task_ioreg_t		tfRegister[8];
+	task_ioreg_t		hobRegister[8];
+	ide_reg_valid_t		tf_out_flags;
+	ide_reg_valid_t		tf_in_flags;
+	int			data_phase;
+	int			command_type;
+	ide_pre_handler_t	*prehandler;
+	ide_handler_t		*handler;
+	ide_post_handler_t	*posthandler;
+	void			*special;	/* valid_t generally */
+	struct request		*rq;		/* copy of request */
+	unsigned long		block;		/* copy of block */
+} ide_task_t;
+
+void ata_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
+void ata_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
+void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);
+void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);
+void taskfile_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
+void taskfile_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
+
+/*
+ * taskfile io for disks for now...
+ */
+ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task);
+
+/*
+ * Builds request from ide_ioctl
+ */
+void do_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, ide_handler_t *handler);
+
+/*
+ * Special Flagged Register Validation Caller
+ */
+// ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task);
+
+ide_startstop_t set_multmode_intr (ide_drive_t *drive);
+ide_startstop_t set_geometry_intr (ide_drive_t *drive);
+ide_startstop_t recal_intr (ide_drive_t *drive);
+ide_startstop_t task_no_data_intr (ide_drive_t *drive);
+ide_startstop_t task_in_intr (ide_drive_t *drive);
+ide_startstop_t task_mulin_intr (ide_drive_t *drive);
+ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq);
+ide_startstop_t task_out_intr (ide_drive_t *drive);
+ide_startstop_t task_mulout_intr (ide_drive_t *drive);
+void ide_init_drive_taskfile (struct request *rq);
+
+int ide_wait_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, byte *buf);
+
+int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *cmd, byte *buf);
+
+ide_pre_handler_t * ide_pre_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile);
+ide_handler_t * ide_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile);
+/* Expects args is a full set of TF registers and parses the command type */
+int ide_cmd_type_parser (ide_task_t *args);
+
+int ide_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+int ide_cmd_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+int ide_task_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+
+#ifdef CONFIG_PKT_TASK_IOCTL
+int pkt_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+#endif /* CONFIG_PKT_TASK_IOCTL */
 
 void ide_delay_50ms (void);
 int system_bus_clock(void);
 
 byte ide_auto_reduce_xfer (ide_drive_t *drive);
 int ide_driveid_update (ide_drive_t *drive);
-int ide_ata66_check (ide_drive_t *drive, byte cmd, byte nsect, byte feature);
+int ide_ata66_check (ide_drive_t *drive, ide_task_t *args);
 int ide_config_drive_speed (ide_drive_t *drive, byte speed);
 byte eighty_ninty_three (ide_drive_t *drive);
-int set_transfer (ide_drive_t *drive, byte cmd, byte nsect, byte feature);
+int set_transfer (ide_drive_t *drive, ide_task_t *args);
 
 /*
  * ide_system_bus_speed() returns what we think is the system VESA/PCI
@@ -911,12 +1040,6 @@
 int ide_system_bus_speed (void);
 
 /*
- * ide_multwrite() transfers a block of up to mcount sectors of data
- * to a drive as part of a disk multwrite operation.
- */
-int ide_multwrite (ide_drive_t *drive, unsigned int mcount);
-
-/*
  * idedisk_input_data() is a wrapper around ide_input_data() which copes
  * with byte-swapping the input data if required.
  */
@@ -951,23 +1074,30 @@
 extern ide_proc_entry_t generic_subdriver_entries[];
 #endif
 
+int ide_reinit_drive (ide_drive_t *drive);
+
 #ifdef _IDE_C
 #ifdef CONFIG_BLK_DEV_IDE
 int ideprobe_init (void);
 #endif /* CONFIG_BLK_DEV_IDE */
 #ifdef CONFIG_BLK_DEV_IDEDISK
+int idedisk_reinit (ide_drive_t *drive);
 int idedisk_init (void);
 #endif /* CONFIG_BLK_DEV_IDEDISK */
 #ifdef CONFIG_BLK_DEV_IDECD
+int ide_cdrom_reinit (ide_drive_t *drive);
 int ide_cdrom_init (void);
 #endif /* CONFIG_BLK_DEV_IDECD */
 #ifdef CONFIG_BLK_DEV_IDETAPE
+int idetape_reinit (ide_drive_t *drive);
 int idetape_init (void);
 #endif /* CONFIG_BLK_DEV_IDETAPE */
 #ifdef CONFIG_BLK_DEV_IDEFLOPPY
+int idefloppy_reinit (ide_drive_t *drive);
 int idefloppy_init (void);
 #endif /* CONFIG_BLK_DEV_IDEFLOPPY */
 #ifdef CONFIG_BLK_DEV_IDESCSI
+int idescsi_reinit (ide_drive_t *drive);
 int idescsi_init (void);
 #endif /* CONFIG_BLK_DEV_IDESCSI */
 #endif /* _IDE_C */
@@ -1006,6 +1136,9 @@
 #endif
 
 void hwif_unregister (ide_hwif_t *hwif);
+
+void export_ide_init_queue (ide_drive_t *drive);
+byte export_probe_for_drive (ide_drive_t *drive);
 
 extern spinlock_t ide_lock;
 
diff -u --recursive --new-file v2.5.2/linux/include/linux/init_task.h linux/include/linux/init_task.h
--- v2.5.2/linux/include/linux/init_task.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/init_task.h	Sat Jan 19 14:32:07 2002
@@ -0,0 +1,86 @@
+#ifndef _LINUX__INIT_TASK_H
+#define _LINUX__INIT_TASK_H
+
+#include <linux/file.h>
+
+#define INIT_FILES \
+{ 							\
+	count:		ATOMIC_INIT(1), 		\
+	file_lock:	RW_LOCK_UNLOCKED, 		\
+	max_fds:	NR_OPEN_DEFAULT, 		\
+	max_fdset:	__FD_SETSIZE, 			\
+	next_fd:	0, 				\
+	fd:		&init_files.fd_array[0], 	\
+	close_on_exec:	&init_files.close_on_exec_init, \
+	open_fds:	&init_files.open_fds_init, 	\
+	close_on_exec_init: { { 0, } }, 		\
+	open_fds_init:	{ { 0, } }, 			\
+	fd_array:	{ NULL, } 			\
+}
+
+#define INIT_MM(name) \
+{			 				\
+	mm_rb:		RB_ROOT,			\
+	pgd:		swapper_pg_dir, 		\
+	mm_users:	ATOMIC_INIT(2), 		\
+	mm_count:	ATOMIC_INIT(1), 		\
+	mmap_sem:	__RWSEM_INITIALIZER(name.mmap_sem), \
+	page_table_lock: SPIN_LOCK_UNLOCKED, 		\
+	mmlist:		LIST_HEAD_INIT(name.mmlist),	\
+}
+
+#define INIT_SIGNALS {	\
+	count:		ATOMIC_INIT(1), 		\
+	action:		{ {{0,}}, }, 			\
+	siglock:	SPIN_LOCK_UNLOCKED 		\
+}
+
+/*
+ *  INIT_TASK is used to set up the first task table, touch at
+ * your own risk!. Base=0, limit=0x1fffff (=2MB)
+ */
+#define INIT_TASK(tsk)	\
+{									\
+    state:		0,						\
+    flags:		0,						\
+    sigpending:		0,						\
+    addr_limit:		KERNEL_DS,					\
+    exec_domain:	&default_exec_domain,				\
+    lock_depth:		-1,						\
+    __nice:		DEF_USER_NICE,					\
+    policy:		SCHED_OTHER,					\
+    cpus_allowed:	-1,						\
+    mm:			NULL,						\
+    active_mm:		&init_mm,					\
+    run_list:		LIST_HEAD_INIT(tsk.run_list),			\
+    time_slice:		NICE_TO_TIMESLICE(DEF_USER_NICE),		\
+    next_task:		&tsk,						\
+    prev_task:		&tsk,						\
+    p_opptr:		&tsk,						\
+    p_pptr:		&tsk,						\
+    thread_group:	LIST_HEAD_INIT(tsk.thread_group),		\
+    wait_chldexit:	__WAIT_QUEUE_HEAD_INITIALIZER(tsk.wait_chldexit),\
+    real_timer:		{						\
+	function:		it_real_fn				\
+    },									\
+    cap_effective:	CAP_INIT_EFF_SET,				\
+    cap_inheritable:	CAP_INIT_INH_SET,				\
+    cap_permitted:	CAP_FULL_SET,					\
+    keep_capabilities:	0,						\
+    rlim:		INIT_RLIMITS,					\
+    user:		INIT_USER,					\
+    comm:		"swapper",					\
+    thread:		INIT_THREAD,					\
+    fs:			&init_fs,					\
+    files:		&init_files,					\
+    sigmask_lock:	SPIN_LOCK_UNLOCKED,				\
+    sig:		&init_signals,					\
+    pending:		{ NULL, &tsk.pending.head, {{0}}},		\
+    blocked:		{{0}},						\
+    alloc_lock:		SPIN_LOCK_UNLOCKED,				\
+    journal_info:	NULL,						\
+}
+
+
+
+#endif
diff -u --recursive --new-file v2.5.2/linux/include/linux/isdn.h linux/include/linux/isdn.h
--- v2.5.2/linux/include/linux/isdn.h	Mon Jan 14 18:25:11 2002
+++ linux/include/linux/isdn.h	Thu Jan 17 14:04:15 2002
@@ -178,8 +178,6 @@
  * the correspondent code in isdn.c
  */
 
-#define ISDN_MINOR_B        0
-#define ISDN_MINOR_BMAX     (ISDN_MAX_CHANNELS-1)
 #define ISDN_MINOR_CTRL     64
 #define ISDN_MINOR_CTRLMAX  (64 + (ISDN_MAX_CHANNELS-1))
 #define ISDN_MINOR_PPP      128
diff -u --recursive --new-file v2.5.2/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.5.2/linux/include/linux/mm.h	Mon Jan 14 18:25:11 2002
+++ linux/include/linux/mm.h	Sat Jan 19 14:30:01 2002
@@ -356,10 +356,10 @@
 extern void shmem_lock(struct file * file, int lock);
 extern int shmem_zero_setup(struct vm_area_struct *);
 
-extern void zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long size);
+extern void zap_page_range(struct vm_area_struct *vma, unsigned long address, unsigned long size);
 extern int copy_page_range(struct mm_struct *dst, struct mm_struct *src, struct vm_area_struct *vma);
-extern int remap_page_range(unsigned long from, unsigned long to, unsigned long size, pgprot_t prot);
-extern int zeromap_page_range(unsigned long from, unsigned long size, pgprot_t prot);
+extern int remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long to, unsigned long size, pgprot_t prot);
+extern int zeromap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long size, pgprot_t prot);
 
 extern int vmtruncate(struct inode * inode, loff_t offset);
 extern pmd_t *FASTCALL(__pmd_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address));
diff -u --recursive --new-file v2.5.2/linux/include/linux/msdos_fs.h linux/include/linux/msdos_fs.h
--- v2.5.2/linux/include/linux/msdos_fs.h	Mon Jan 14 18:25:11 2002
+++ linux/include/linux/msdos_fs.h	Tue Jan 15 10:58:53 2002
@@ -19,13 +19,14 @@
 #define MSDOS_DPS_BITS	4 /* log2(MSDOS_DPS) */
 #define MSDOS_DIR_BITS	5 /* log2(sizeof(struct msdos_dir_entry)) */
 
+/* directory limit */
+#define FAT_MAX_DIR_ENTRIES	(65536)
+#define FAT_MAX_DIR_SIZE	(FAT_MAX_DIR_ENTRIES << MSDOS_DIR_BITS)
+
 #define MSDOS_SUPER_MAGIC 0x4d44 /* MD */
 
 #define FAT_CACHE    8 /* FAT cache size */
 
-#define MSDOS_MAX_EXTRA	3 /* tolerate up to that number of clusters which are
-			     inaccessible because the FAT is too short */
-
 #define ATTR_RO      1  /* read-only */
 #define ATTR_HIDDEN  2  /* hidden */
 #define ATTR_SYS     4  /* system */
@@ -48,11 +49,6 @@
 #define CASE_LOWER_BASE 8	/* base is lower case */
 #define CASE_LOWER_EXT  16	/* extension is lower case */
 
-#define SCAN_ANY     0  /* either hidden or not */
-#define SCAN_HID     1  /* only hidden */
-#define SCAN_NOTHID  2  /* only not hidden */
-#define SCAN_NOTANY  3  /* test name, then use SCAN_HID or SCAN_NOTHID */
-
 #define DELETED_FLAG 0xe5 /* marks file as deleted when in name[0] */
 #define IS_FREE(n) (!*(n) || *(const unsigned char *) (n) == DELETED_FLAG)
 
@@ -78,8 +74,8 @@
 
 #define FAT_FSINFO_SIG1		0x41615252
 #define FAT_FSINFO_SIG2		0x61417272
-#define IS_FSINFO(x)		(CF_LE_L((x)->signature1) == FAT_FSINFO_SIG1	 \
-				 && CF_LE_L((x)->signature2) == FAT_FSINFO_SIG2)
+#define IS_FSINFO(x)	(CF_LE_L((x)->signature1) == FAT_FSINFO_SIG1	\
+			 && CF_LE_L((x)->signature2) == FAT_FSINFO_SIG2)
 
 /*
  * Inode flags
@@ -184,10 +180,6 @@
 	int ino;		       /* ino for the file */
 };
 
-/* Determine whether this FS has kB-aligned data. */
-#define MSDOS_CAN_BMAP(mib) (!(((mib)->cluster_size & 1) || \
-    ((mib)->data_start & 1)))
-
 /* Convert attribute bits and a mask to the UNIX mode. */
 #define MSDOS_MKMODE(a,m) (m & (a & ATTR_RO ? S_IRUGO|S_IXUGO : S_IRWXUGO))
 
@@ -297,7 +289,7 @@
 extern int fat_notify_change(struct dentry * dentry, struct iattr * attr);
 
 /* fat/misc.c */
-extern void fat_fs_panic(struct super_block *s, const char *msg);
+extern void fat_fs_panic(struct super_block *s, const char *fmt, ...);
 extern int fat_is_binary(char conversion, char *extension);
 extern void lock_fat(struct super_block *sb);
 extern void unlock_fat(struct super_block *sb);
diff -u --recursive --new-file v2.5.2/linux/include/linux/mtd/cfi.h linux/include/linux/mtd/cfi.h
--- v2.5.2/linux/include/linux/mtd/cfi.h	Thu Oct  4 15:13:18 2001
+++ linux/include/linux/mtd/cfi.h	Tue Jan 15 13:53:51 2002
@@ -368,7 +368,7 @@
 static inline void cfi_udelay(int us)
 {
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-	if (current->need_resched) {
+	if (need_resched()) {
 		unsigned long t = us * HZ / 1000000;
 		if (t < 1)
 			t = 1;
diff -u --recursive --new-file v2.5.2/linux/include/linux/netlink.h linux/include/linux/netlink.h
--- v2.5.2/linux/include/linux/netlink.h	Thu Jul 26 14:00:17 2001
+++ linux/include/linux/netlink.h	Tue Jan 15 10:56:35 2002
@@ -5,6 +5,7 @@
 #define NETLINK_SKIP		1	/* Reserved for ENskip  			*/
 #define NETLINK_USERSOCK	2	/* Reserved for user mode socket protocols 	*/
 #define NETLINK_FIREWALL	3	/* Firewalling hook				*/
+#define NETLINK_TCPDIAG		4	/* TCP socket monitoring			*/
 #define NETLINK_ARPD		8
 #define NETLINK_ROUTE6		11	/* af_inet6 route comm channel */
 #define NETLINK_IP6_FW		13
diff -u --recursive --new-file v2.5.2/linux/include/linux/reiserfs_fs_sb.h linux/include/linux/reiserfs_fs_sb.h
--- v2.5.2/linux/include/linux/reiserfs_fs_sb.h	Mon Jan 14 18:25:11 2002
+++ linux/include/linux/reiserfs_fs_sb.h	Sat Jan 19 14:29:59 2002
@@ -300,7 +300,7 @@
   int j_free_bitmap_nodes ;
   int j_used_bitmap_nodes ;
   struct list_head j_bitmap_nodes ;
-  struct inode j_dummy_inode ;
+  struct list_head j_dirty_buffers ;
   struct reiserfs_list_bitmap j_list_bitmap[JOURNAL_NUM_BITMAPS] ;	/* array of bitmaps to record the deleted blocks */
   struct reiserfs_journal_list j_journal_list[JOURNAL_LIST_COUNT] ;	    /* array of all the journal lists */
   struct reiserfs_journal_cnode *j_hash_table[JOURNAL_HASH_SIZE] ; 	    /* hash table for real buffer heads in current trans */ 
diff -u --recursive --new-file v2.5.2/linux/include/linux/rtnetlink.h linux/include/linux/rtnetlink.h
--- v2.5.2/linux/include/linux/rtnetlink.h	Thu Jul 26 14:01:13 2001
+++ linux/include/linux/rtnetlink.h	Tue Jan 15 10:56:35 2002
@@ -546,7 +546,6 @@
 
 extern int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, int len);
 
-#ifdef CONFIG_RTNETLINK
 extern struct sock *rtnl;
 
 struct rtnetlink_link
@@ -568,12 +567,6 @@
 
 extern void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change);
 
-#else
-
-#define rtmsg_ifinfo(a,b,c) do { } while (0)
-
-#endif
-
 extern struct semaphore rtnl_sem;
 
 #define rtnl_exlock()		do { } while(0)
@@ -583,14 +576,10 @@
 #define rtnl_shlock()		down(&rtnl_sem)
 #define rtnl_shlock_nowait()	down_trylock(&rtnl_sem)
 
-#ifndef CONFIG_RTNETLINK
-#define rtnl_shunlock()	up(&rtnl_sem)
-#else
 #define rtnl_shunlock()	do { up(&rtnl_sem); \
 		             if (rtnl && rtnl->receive_queue.qlen) \
 				     rtnl->data_ready(rtnl, 0); \
 		        } while(0)
-#endif
 
 extern void rtnl_lock(void);
 extern void rtnl_unlock(void);
diff -u --recursive --new-file v2.5.2/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.5.2/linux/include/linux/sched.h	Mon Jan 14 18:25:11 2002
+++ linux/include/linux/sched.h	Sat Jan 19 14:30:00 2002
@@ -25,6 +25,7 @@
 #include <linux/signal.h>
 #include <linux/securebits.h>
 #include <linux/fs_struct.h>
+#include <linux/compiler.h>
 
 struct exec_domain;
 
@@ -136,6 +137,8 @@
 extern rwlock_t tasklist_lock;
 extern spinlock_t mmlist_lock;
 
+typedef struct task_struct task_t;
+
 extern void sched_init(void);
 extern void init_idle(void);
 extern void show_state(void);
@@ -144,8 +147,7 @@
 extern void update_process_times(int user);
 extern void update_one_process(struct task_struct *p, unsigned long user,
 			       unsigned long system, int cpu);
-extern void expire_task(struct task_struct *p);
-extern void idle_tick(void);
+extern void scheduler_tick(struct task_struct *p);
 
 #define	MAX_SCHEDULE_TIMEOUT	LONG_MAX
 extern signed long FASTCALL(schedule_timeout(signed long timeout));
@@ -156,44 +158,7 @@
 extern int start_context_thread(void);
 extern int current_is_keventd(void);
 
-/*
- * The default fd array needs to be at least BITS_PER_LONG,
- * as this is the granularity returned by copy_fdset().
- */
-#define NR_OPEN_DEFAULT BITS_PER_LONG
-
 struct namespace;
-/*
- * Open file table structure
- */
-struct files_struct {
-	atomic_t count;
-	rwlock_t file_lock;	/* Protects all the below members.  Nests inside tsk->alloc_lock */
-	int max_fds;
-	int max_fdset;
-	int next_fd;
-	struct file ** fd;	/* current fd array */
-	fd_set *close_on_exec;
-	fd_set *open_fds;
-	fd_set close_on_exec_init;
-	fd_set open_fds_init;
-	struct file * fd_array[NR_OPEN_DEFAULT];
-};
-
-#define INIT_FILES \
-{ 							\
-	count:		ATOMIC_INIT(1), 		\
-	file_lock:	RW_LOCK_UNLOCKED, 		\
-	max_fds:	NR_OPEN_DEFAULT, 		\
-	max_fdset:	__FD_SETSIZE, 			\
-	next_fd:	0, 				\
-	fd:		&init_files.fd_array[0], 	\
-	close_on_exec:	&init_files.close_on_exec_init, \
-	open_fds:	&init_files.open_fds_init, 	\
-	close_on_exec_init: { { 0, } }, 		\
-	open_fds_init:	{ { 0, } }, 			\
-	fd_array:	{ NULL, } 			\
-}
 
 /* Maximum number of active map areas.. This is a random (large) number */
 #define MAX_MAP_COUNT	(65536)
@@ -230,17 +195,6 @@
 
 extern int mmlist_nr;
 
-#define INIT_MM(name) \
-{			 				\
-	mm_rb:		RB_ROOT,			\
-	pgd:		swapper_pg_dir, 		\
-	mm_users:	ATOMIC_INIT(2), 		\
-	mm_count:	ATOMIC_INIT(1), 		\
-	mmap_sem:	__RWSEM_INITIALIZER(name.mmap_sem), \
-	page_table_lock: SPIN_LOCK_UNLOCKED, 		\
-	mmlist:		LIST_HEAD_INIT(name.mmlist),	\
-}
-
 struct signal_struct {
 	atomic_t		count;
 	struct k_sigaction	action[_NSIG];
@@ -248,12 +202,6 @@
 };
 
 
-#define INIT_SIGNALS {	\
-	count:		ATOMIC_INIT(1), 		\
-	action:		{ {{0,}}, }, 			\
-	siglock:	SPIN_LOCK_UNLOCKED 		\
-}
-
 /*
  * Some day this will be a full-fledged user tracking system..
  */
@@ -275,7 +223,6 @@
 extern struct user_struct root_user;
 #define INIT_USER (&root_user)
 
-typedef struct task_struct task_t;
 typedef struct prio_array prio_array_t;
 
 struct task_struct {
@@ -305,7 +252,10 @@
 	prio_array_t *array;
 
 	unsigned int time_slice;
-	unsigned long sleep_jtime;
+
+	#define MAX_SLEEP_AVG (2*HZ)
+	unsigned long sleep_avg;
+	unsigned long sleep_timestamp;
 
 	unsigned long policy;
 	unsigned long cpus_allowed;
@@ -444,56 +394,47 @@
  * them out at 128 to make it easier to search the
  * scheduler bitmap.
  */
-#define MAX_RT_PRIO	128
+#define MAX_RT_PRIO		128
 /*
  * The lower the priority of a process, the more likely it is
  * to run. Priority of a process goes from 0 to 167. The 0-99
  * priority range is allocated to RT tasks, the 128-167 range
  * is for SCHED_OTHER tasks.
  */
-#define MAX_PRIO	(MAX_RT_PRIO+40)
-#define DEF_USER_NICE	0
+#define MAX_PRIO		(MAX_RT_PRIO + 40)
 
 /*
  * Scales user-nice values [ -20 ... 0 ... 19 ]
- * to static priority [ 24 ... 63 (MAX_PRIO-1) ]
+ * to static priority [ 128 ... 167 (MAX_PRIO-1) ]
  *
- * User-nice value of -20 == static priority 24, and
- * user-nice value 19 == static priority 63. The lower
+ * User-nice value of -20 == static priority 128, and
+ * user-nice value 19 == static priority 167. The lower
  * the priority value, the higher the task's priority.
- *
- * Note that while static priority cannot go below 24,
- * the priority of a process can go as low as 0.
  */
-#define NICE_TO_PRIO(n)	(MAX_PRIO-1 + (n) - 19)
-
-#define DEF_PRIO NICE_TO_PRIO(DEF_USER_NICE)
+#define NICE_TO_PRIO(n)		(MAX_RT_PRIO + (n) + 20)
+#define DEF_USER_NICE		0
 
 /*
- * Default timeslice is 90 msecs, maximum is 150 msecs.
- * Minimum timeslice is 20 msecs.
+ * Default timeslice is 90 msecs, maximum is 180 msecs.
+ * Minimum timeslice is 10 msecs.
  */
-#define MIN_TIMESLICE	( 20 * HZ / 1000)
-#define MAX_TIMESLICE	(150 * HZ / 1000)
+#define MIN_TIMESLICE		( 10 * HZ / 1000)
+#define MAX_TIMESLICE		(180 * HZ / 1000)
 
-#define USER_PRIO(p) ((p)-MAX_RT_PRIO)
-#define MAX_USER_PRIO (USER_PRIO(MAX_PRIO))
+#define USER_PRIO(p)		((p)-MAX_RT_PRIO)
+#define MAX_USER_PRIO		(USER_PRIO(MAX_PRIO))
 
 /*
- * PRIO_TO_TIMESLICE scales priority values [ 100 ... 139  ]
- * to initial time slice values [ MAX_TIMESLICE (150 msec) ... 2 ]
+ * NICE_TO_TIMESLICE scales nice values [ -20 ... 19 ]
+ * to time slice values.
  *
  * The higher a process's priority, the bigger timeslices
  * it gets during one round of execution. But even the lowest
  * priority process gets MIN_TIMESLICE worth of execution time.
  */
-#define PRIO_TO_TIMESLICE(p) \
-	((( (MAX_USER_PRIO-1-USER_PRIO(p))*(MAX_TIMESLICE-MIN_TIMESLICE) + \
-		MAX_USER_PRIO-1) / MAX_USER_PRIO) + MIN_TIMESLICE)
-
-#define RT_PRIO_TO_TIMESLICE(p) \
-	((( (MAX_RT_PRIO-(p)-1)*(MAX_TIMESLICE-MIN_TIMESLICE) + \
-			MAX_RT_PRIO-1) / MAX_RT_PRIO) + MIN_TIMESLICE)
+
+#define NICE_TO_TIMESLICE(n) (MIN_TIMESLICE + \
+	((MAX_TIMESLICE - MIN_TIMESLICE) * (19-(n))) / 39)
 
 extern void set_cpus_allowed(task_t *p, unsigned long new_mask);
 extern void set_user_nice(task_t *p, long nice);
@@ -505,53 +446,6 @@
  */
 extern struct exec_domain	default_exec_domain;
 
-/*
- *  INIT_TASK is used to set up the first task table, touch at
- * your own risk!. Base=0, limit=0x1fffff (=2MB)
- */
-#define INIT_TASK(tsk)	\
-{									\
-    state:		0,						\
-    flags:		0,						\
-    sigpending:		0,						\
-    addr_limit:		KERNEL_DS,					\
-    exec_domain:	&default_exec_domain,				\
-    lock_depth:		-1,						\
-    __nice:		DEF_USER_NICE,					\
-    policy:		SCHED_OTHER,					\
-    cpus_allowed:	-1,						\
-    mm:			NULL,						\
-    active_mm:		&init_mm,					\
-    run_list:		LIST_HEAD_INIT(tsk.run_list),			\
-    time_slice:		PRIO_TO_TIMESLICE(DEF_PRIO),			\
-    next_task:		&tsk,						\
-    prev_task:		&tsk,						\
-    p_opptr:		&tsk,						\
-    p_pptr:		&tsk,						\
-    thread_group:	LIST_HEAD_INIT(tsk.thread_group),		\
-    wait_chldexit:	__WAIT_QUEUE_HEAD_INITIALIZER(tsk.wait_chldexit),\
-    real_timer:		{						\
-	function:		it_real_fn				\
-    },									\
-    cap_effective:	CAP_INIT_EFF_SET,				\
-    cap_inheritable:	CAP_INIT_INH_SET,				\
-    cap_permitted:	CAP_FULL_SET,					\
-    keep_capabilities:	0,						\
-    rlim:		INIT_RLIMITS,					\
-    user:		INIT_USER,					\
-    comm:		"swapper",					\
-    thread:		INIT_THREAD,					\
-    fs:			&init_fs,					\
-    files:		&init_files,					\
-    sigmask_lock:	SPIN_LOCK_UNLOCKED,				\
-    sig:		&init_signals,					\
-    pending:		{ NULL, &tsk.pending.head, {{0}}},		\
-    blocked:		{{0}},						\
-    alloc_lock:		SPIN_LOCK_UNLOCKED,				\
-    journal_info:	NULL,						\
-}
-
-
 #ifndef INIT_TASK_SIZE
 # define INIT_TASK_SIZE	2048*sizeof(long)
 #endif
@@ -668,6 +562,17 @@
 static inline int signal_pending(struct task_struct *p)
 {
 	return (p->sigpending != 0);
+}
+  
+static inline int need_resched(void)
+{
+	return unlikely(current->need_resched != 0);
+}
+
+static inline void cond_resched(void)
+{
+	if (need_resched())
+		schedule();
 }
 
 /*
diff -u --recursive --new-file v2.5.2/linux/include/linux/tcp_diag.h linux/include/linux/tcp_diag.h
--- v2.5.2/linux/include/linux/tcp_diag.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/tcp_diag.h	Tue Jan 15 10:56:35 2002
@@ -0,0 +1,116 @@
+#ifndef _TCP_DIAG_H_
+#define _TCP_DIAG_H_ 1
+
+/* Just some random number */
+#define TCPDIAG_GETSOCK 18
+
+/* Socket identity */
+struct tcpdiag_sockid
+{
+	__u16	tcpdiag_sport;
+	__u16	tcpdiag_dport;
+	__u32	tcpdiag_src[4];
+	__u32	tcpdiag_dst[4];
+	__u32	tcpdiag_if;
+	__u32	tcpdiag_cookie[2];
+#define TCPDIAG_NOCOOKIE (~0U)
+};
+
+/* Request structure */
+
+struct tcpdiagreq
+{
+	__u8	tcpdiag_family;		/* Family of addresses. */
+	__u8	tcpdiag_src_len;
+	__u8	tcpdiag_dst_len;
+	__u8	tcpdiag_ext;		/* Query extended information */
+
+	struct tcpdiag_sockid id;
+
+	__u32	tcpdiag_states;		/* States to dump */
+	__u32	tcpdiag_dbs;		/* Tables to dump (NI) */
+};
+
+enum
+{
+	TCPDIAG_REQ_NONE,
+	TCPDIAG_REQ_BYTECODE,
+};
+
+#define TCPDIAG_REQ_MAX TCPDIAG_REQ_BYTECODE
+
+/* Bytecode is sequence of 4 byte commands followed by variable arguments.
+ * All the commands identified by "code" are conditional jumps forward:
+ * to offset cc+"yes" or to offset cc+"no". "yes" is supposed to be
+ * length of the command and its arguments.
+ */
+ 
+struct tcpdiag_bc_op
+{
+	unsigned char	code;
+	unsigned char	yes;
+	unsigned short	no;
+};
+
+enum
+{
+	TCPDIAG_BC_NOP,
+	TCPDIAG_BC_JMP,
+	TCPDIAG_BC_S_GE,
+	TCPDIAG_BC_S_LE,
+	TCPDIAG_BC_D_GE,
+	TCPDIAG_BC_D_LE,
+	TCPDIAG_BC_AUTO,
+	TCPDIAG_BC_S_COND,
+	TCPDIAG_BC_D_COND,
+};
+
+struct tcpdiag_hostcond
+{
+	__u8	family;
+	__u8	prefix_len;
+	int	port;
+	__u32	addr[0];
+};
+
+/* Base info structure. It contains socket identity (addrs/ports/cookie)
+ * and, alas, the information shown by netstat. */
+struct tcpdiagmsg
+{
+	__u8	tcpdiag_family;
+	__u8	tcpdiag_state;
+	__u8	tcpdiag_timer;
+	__u8	tcpdiag_retrans;
+
+	struct tcpdiag_sockid id;
+
+	__u32	tcpdiag_expires;
+	__u32	tcpdiag_rqueue;
+	__u32	tcpdiag_wqueue;
+	__u32	tcpdiag_uid;
+	__u32	tcpdiag_inode;
+};
+
+/* Extensions */
+
+enum
+{
+	TCPDIAG_NONE,
+	TCPDIAG_MEMINFO,
+	TCPDIAG_INFO,
+};
+
+#define TCPDIAG_MAX TCPDIAG_INFO
+
+
+/* TCPDIAG_MEM */
+
+struct tcpdiag_meminfo
+{
+	__u32	tcpdiag_rmem;
+	__u32	tcpdiag_wmem;
+	__u32	tcpdiag_fmem;
+	__u32	tcpdiag_tmem;
+};
+
+#endif /* _TCP_DIAG_H_ */
diff -u --recursive --new-file v2.5.2/linux/include/linux/videodev.h linux/include/linux/videodev.h
--- v2.5.2/linux/include/linux/videodev.h	Fri Nov  9 14:11:15 2001
+++ linux/include/linux/videodev.h	Tue Jan 15 10:56:36 2002
@@ -8,6 +8,7 @@
 
 #include <linux/poll.h>
 #include <linux/devfs_fs_kernel.h>
+#include <linux/mm.h>
 
 struct video_device
 {
@@ -25,7 +26,7 @@
 	unsigned int (*poll)(struct video_device *, struct file *, poll_table *);
 #endif
 	int (*ioctl)(struct video_device *, unsigned int , void *);
-	int (*mmap)(struct video_device *, const char *, unsigned long);
+	int (*mmap)(struct vm_area_struct *vma, struct video_device *, const char *, unsigned long);
 	int (*initialize)(struct video_device *);	
 	void *priv;		/* Used to be 'private' but that upsets C++ */
 	int busy;
diff -u --recursive --new-file v2.5.2/linux/include/net/dn_fib.h linux/include/net/dn_fib.h
--- v2.5.2/linux/include/net/dn_fib.h	Mon Dec 11 13:33:56 2000
+++ linux/include/net/dn_fib.h	Tue Jan 15 10:56:35 2002
@@ -113,9 +113,7 @@
 	int (*get_info)(struct dn_fib_table *table, char *buf,
 			int first, int count);
 #endif /* CONFIG_PROC_FS */
-#ifdef CONFIG_RTNETLINK
 	int (*dump)(struct dn_fib_table *t, struct sk_buff *skb, struct netlink_callback *cb);
-#endif /* CONFIG_RTNETLINK */
 
 	unsigned char data[0];
 };
@@ -163,7 +161,6 @@
 /*
  * rtnetlink interface
  */
-#ifdef CONFIG_RTNETLINK
 extern int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
 extern int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
 extern int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb);
@@ -171,7 +168,6 @@
 extern int dn_fib_rtm_delrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
 extern int dn_fib_rtm_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
 extern int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb);
-#endif /* CONFIG_RTNETLINK */
 
 #define DN_NUM_TABLES 255
 #define DN_MIN_TABLE 1
diff -u --recursive --new-file v2.5.2/linux/include/net/inetpeer.h linux/include/net/inetpeer.h
--- v2.5.2/linux/include/net/inetpeer.h	Thu Nov 22 11:47:11 2001
+++ linux/include/net/inetpeer.h	Sat Jan 19 14:31:09 2002
@@ -1,7 +1,7 @@
 /*
  *		INETPEER - A storage for permanent information about peers
  *
- *  Version:	$Id: inetpeer.h,v 1.1 2000/01/06 00:41:51 davem Exp $
+ *  Version:	$Id: inetpeer.h,v 1.2 2002/01/12 07:54:56 davem Exp $
  *
  *  Authors:	Andrey V. Savochkin <saw@msu.ru>
  */
@@ -38,7 +38,7 @@
 extern struct inet_peer *inet_peer_unused_head;
 extern struct inet_peer **inet_peer_unused_tailp;
 /* can be called from BH context or outside */
-extern inline void	inet_putpeer(struct inet_peer *p)
+static inline void	inet_putpeer(struct inet_peer *p)
 {
 	spin_lock_bh(&inet_peer_unused_lock);
 	if (atomic_dec_and_test(&p->refcnt)) {
@@ -53,7 +53,7 @@
 
 extern spinlock_t inet_peer_idlock;
 /* can be called with or without local BH being disabled */
-extern inline __u16	inet_getid(struct inet_peer *p)
+static inline __u16	inet_getid(struct inet_peer *p)
 {
 	__u16 id;
 
diff -u --recursive --new-file v2.5.2/linux/include/net/sock.h linux/include/net/sock.h
--- v2.5.2/linux/include/net/sock.h	Thu Nov 22 11:47:15 2001
+++ linux/include/net/sock.h	Sat Jan 19 14:31:12 2002
@@ -643,9 +643,7 @@
 #if defined(CONFIG_PPPOE) || defined(CONFIG_PPPOE_MODULE)
 		struct pppox_opt	*pppox;
 #endif
-#ifdef CONFIG_NETLINK
 		struct netlink_opt	*af_netlink;
-#endif
 #if defined(CONFIG_ECONET) || defined(CONFIG_ECONET_MODULE)
 		struct econet_opt	*af_econet;
 #endif
@@ -828,6 +826,11 @@
 						     unsigned long size,
 						     int noblock,
 						     int *errcode);
+extern struct sk_buff 		*sock_alloc_send_pskb(struct sock *sk,
+						      unsigned long header_len,
+						      unsigned long data_len,
+						      int noblock,
+						      int *errcode);
 extern void *sock_kmalloc(struct sock *sk, int size, int priority);
 extern void sock_kfree_s(struct sock *sk, void *mem, int size);
 
diff -u --recursive --new-file v2.5.2/linux/include/scsi/sg.h linux/include/scsi/sg.h
--- v2.5.2/linux/include/scsi/sg.h	Fri Sep  7 09:28:37 2001
+++ linux/include/scsi/sg.h	Thu Jan 17 13:59:33 2002
@@ -11,78 +11,71 @@
 Version 2 and 3 extensions to driver:
 *       Copyright (C) 1998 - 2001 Douglas Gilbert
 
-    Version: 3.1.20 (20010814)
-    This version is for 2.4 series kernels.
+    Version: 3.5.23 (20011231)
+    This version is for 2.5 series kernels.
 
-    Changes since 3.1.19 (20010623)
-	- add SG_GET_ACCESS_COUNT ioctl 
-	- make open() increment and close() decrement access_count
-	- only register first 256 devices, reject subsequent devices
-    Changes since 3.1.18 (20010505)
-	- fix bug that caused long wait when large buffer requested
-	- fix leak in error case of sg_new_read() [report: Eric Barton]
-	- add 'online' column to /proc/scsi/sg/devices
-    Changes since 3.1.17 (20000921)
-    	- add CAP_SYS_RAWIO capability for sensitive stuff
-    	- compile in dio stuff, procfs 'allow_dio' defaulted off (0)
-	- make premature close and detach more robust
-	- lun masked into commands <= SCSI_2
-	- poll() and async notification now yield POLL_HUP on detach
-	- various 3rd party tweaks tracking lk 2.4 internal changes
+    Changes since 3.1.22 (20011208)
+    	- branch sg driver for lk 2.5 series
+    	- remove lock_kernel() from sg_close()
+    	- remove code based on scsi mid level dma pool
+    	- change scatterlist 'address' to use page + offset
+    	- add SG_INTERFACE_ID_ORIG
 
 Map of SG verions to the Linux kernels in which they appear:
        ----------        ----------------------------------
        original          all kernels < 2.2.6
-       2.1.38            2.2.16
-       2.1.39            2.2.17 - 2.2.19
+       2.1.40            2.2.20
        3.0.x             optional version 3 sg driver for 2.2 series
-       3.1.17            2.4.0 ++
+       3.1.17++          2.4.0++
+       3.5.23++          2.5.0++
 
 Major new features in SG 3.x driver (cf SG 2.x drivers)
 	- SG_IO ioctl() combines function if write() and read()
 	- new interface (sg_io_hdr_t) but still supports old interface
-	- scatter/gather in user space and direct IO supported
+	- scatter/gather in user space, direct IO, and mmap supported
 
- The term "indirect IO" refers a method by which data is DMAed into kernel
- buffers from the hardware and afterwards is transferred into the user
- space (or vice versa if you are writing). Transfer speeds of up to 20 to
- 30MBytes/sec have been measured using indirect IO. For faster throughputs
- "direct IO" which cuts out the double handling of data is required.
- Direct IO is supported by the SG 3.x drivers on 2.4 series Linux kernels
- and requires the use of the new interface.
-
- Requests for direct IO with the new interface will automatically fall back
- to indirect IO mode if they cannot be fulfilled. An example of such a case
- is an ISA SCSI adapter which is only capable of DMAing to the lower 16MB of
- memory due to the architecture of ISA. The 'info' field in the new
- interface indicates whether a direct or indirect data transfer took place.
-
- Obtaining memory for the kernel buffers used in indirect IO is done by
- first checking if the "reserved buffer" for the current file descriptor
- is available and large enough. If these conditions are _not_ met then
- kernel memory is obtained on a per SCSI command basis. This corresponds
- to a write(), read() sequence or a SG_IO ioctl() call. Further, the
- kernel memory that is suitable for DMA may be constrained by the
- architecture of the SCSI adapter (e.g. ISA adapters).
+ The normal action of this driver is to use the adapter (HBA) driver to DMA
+ data into kernel buffers and then use the CPU to copy the data into the 
+ user space (vice versa for writes). That is called "indirect" IO due to 
+ the double handling of data. There are two methods offered to remove the
+ redundant copy: 1) direct IO which uses the kernel kiobuf mechanism and 
+ 2) using the mmap() system call to map the reserve buffer (this driver has 
+ one reserve buffer per fd) into the user space. Both have their advantages.
+ In terms of absolute speed mmap() is faster. If speed is not a concern, 
+ indirect IO should be fine. Read the documentation for more information.
 
  ** N.B. To use direct IO 'echo 1 > /proc/scsi/sg/allow_dio' may be
          needed. That pseudo file's content is defaulted to 0. **
+ 
+ Historical note: this SCSI pass-through driver has been known as "sg" for 
+ a decade. In broader kernel discussions "sg" is used to refer to scatter
+ gather techniques. The context should clarify which "sg" is referred to.
 
  Documentation
  =============
- A web site for SG device drivers can be found at:
+ A web site for the SG device driver can be found at:
 	http://www.torque.net/sg  [alternatively check the MAINTAINERS file]
- The main documents are still based on 2.x versions:
+ The documentation for the sg version 3 driver can be found at:
+ 	http://www.torque.net/sg/p/sg_v3_ho.html
+ This is a rendering from DocBook source [change the extension to "sgml"
+ or "xml"]. There are renderings in "ps", "pdf", "rtf" and "txt" (soon).
+
+ The older, version 2 documents discuss the original sg interface in detail:
 	http://www.torque.net/sg/p/scsi-generic.txt
 	http://www.torque.net/sg/p/scsi-generic_long.txt
- Documentation on the changes and additions in 3.x version of the sg driver
- can be found at: http://www.torque.net/sg/p/scsi-generic_v3.txt
  A version of this document (potentially out of date) may also be found in
  the kernel source tree, probably at:
         /usr/src/linux/Documentation/scsi-generic.txt .
- Utility and test programs are available at the sg web site.
+
+ Utility and test programs are available at the sg web site. They are 
+ bundled as sg_utils (for the lk 2.2 series) and sg3_utils (for the
+ lk 2.4 series).
+
+ There is a HOWTO on the Linux SCSI subsystem in the lk 2.4 series at:
+ 	http://www.linuxdoc.org/HOWTO/SCSI-2.4-HOWTO
 */
 
+
 /* New interface introduced in the 3.x SG drivers follows */
 
 typedef struct sg_iovec /* same structure as used by readv() Linux system */
@@ -119,20 +112,23 @@
     unsigned int info;          /* [o] auxiliary information */
 } sg_io_hdr_t;  /* 64 bytes long (on i386) */
 
+#define SG_INTERFACE_ID_ORIG 'S'
+
 /* Use negative values to flag difference from original sg_header structure */
-#define SG_DXFER_NONE -1        /* e.g. a SCSI Test Unit Ready command */
-#define SG_DXFER_TO_DEV -2      /* e.g. a SCSI WRITE command */
-#define SG_DXFER_FROM_DEV -3    /* e.g. a SCSI READ command */
-#define SG_DXFER_TO_FROM_DEV -4 /* treated like SG_DXFER_FROM_DEV with the
+#define SG_DXFER_NONE (-1)      /* e.g. a SCSI Test Unit Ready command */
+#define SG_DXFER_TO_DEV (-2)    /* e.g. a SCSI WRITE command */
+#define SG_DXFER_FROM_DEV (-3)  /* e.g. a SCSI READ command */
+#define SG_DXFER_TO_FROM_DEV (-4) /* treated like SG_DXFER_FROM_DEV with the
 				   additional property than during indirect
 				   IO the user buffer is copied into the
 				   kernel buffers before the transfer */
-#define SG_DXFER_UNKNOWN -5     /* Unknown data direction */
+#define SG_DXFER_UNKNOWN (-5)   /* Unknown data direction */
 
 /* following flag values can be "or"-ed together */
 #define SG_FLAG_DIRECT_IO 1     /* default is indirect IO */
-#define SG_FLAG_LUN_INHIBIT 2   /* default is to put device's lun into */
-				/* the 2nd byte of SCSI command */
+#define SG_FLAG_LUN_INHIBIT 2   /* default is overwrite lun in SCSI */
+				/* command block (when <= SCSI_2) */
+#define SG_FLAG_MMAP_IO 4       /* request memory mapped IO */
 #define SG_FLAG_NO_DXFER 0x10000 /* no transfer of kernel buffers to/from */
 				/* user space (debug indirect IO) */
 
diff -u --recursive --new-file v2.5.2/linux/kernel/exit.c linux/kernel/exit.c
--- v2.5.2/linux/kernel/exit.c	Mon Jan 14 18:25:11 2002
+++ linux/kernel/exit.c	Tue Jan 15 11:07:01 2002
@@ -17,6 +17,7 @@
 #ifdef CONFIG_BSD_PROCESS_ACCT
 #include <linux/acct.h>
 #endif
+#include <linux/file.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v2.5.2/linux/kernel/fork.c linux/kernel/fork.c
--- v2.5.2/linux/kernel/fork.c	Mon Jan 14 18:25:11 2002
+++ linux/kernel/fork.c	Tue Jan 15 14:33:55 2002
@@ -21,6 +21,7 @@
 #include <linux/completion.h>
 #include <linux/namespace.h>
 #include <linux/personality.h>
+#include <linux/file.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -703,9 +704,13 @@
 		 * runqueue lock is not a problem.
 		 */
 		current->time_slice = 1;
-		expire_task(current);
+		scheduler_tick(current);
 	}
+	p->sleep_timestamp = jiffies;
 	__restore_flags(flags);
+
+	if (p->policy == SCHED_OTHER)
+		p->prio = MAX_PRIO - 1 - ((MAX_PRIO - 1 - p->prio) * 1) / 3;
 
 	/*
 	 * Ok, add it to the run-queues and make it
diff -u --recursive --new-file v2.5.2/linux/kernel/kmod.c linux/kernel/kmod.c
--- v2.5.2/linux/kernel/kmod.c	Mon Jan 14 18:25:11 2002
+++ linux/kernel/kmod.c	Tue Jan 15 11:07:01 2002
@@ -27,6 +27,7 @@
 #include <linux/slab.h>
 #include <linux/namespace.h>
 #include <linux/completion.h>
+#include <linux/file.h>
 
 #include <asm/uaccess.h>
 
diff -u --recursive --new-file v2.5.2/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.5.2/linux/kernel/ksyms.c	Mon Jan 14 18:25:11 2002
+++ linux/kernel/ksyms.c	Thu Jan 17 14:30:00 2002
@@ -85,9 +85,6 @@
 EXPORT_SYMBOL(do_munmap);
 EXPORT_SYMBOL(do_brk);
 EXPORT_SYMBOL(exit_mm);
-EXPORT_SYMBOL(exit_files);
-EXPORT_SYMBOL(exit_fs);
-EXPORT_SYMBOL(exit_sighand);
 
 /* internal kernel memory management */
 EXPORT_SYMBOL(_alloc_pages);
@@ -140,6 +137,7 @@
 EXPORT_SYMBOL(iunique);
 EXPORT_SYMBOL(iget4);
 EXPORT_SYMBOL(iput);
+EXPORT_SYMBOL(inode_init_once);
 EXPORT_SYMBOL(force_delete);
 EXPORT_SYMBOL(follow_up);
 EXPORT_SYMBOL(follow_down);
@@ -505,17 +503,16 @@
 /* Added to make file system as module */
 EXPORT_SYMBOL(sys_tz);
 EXPORT_SYMBOL(file_fsync);
-EXPORT_SYMBOL(fsync_inode_buffers);
-EXPORT_SYMBOL(fsync_inode_data_buffers);
+EXPORT_SYMBOL(fsync_buffers_list);
 EXPORT_SYMBOL(clear_inode);
 EXPORT_SYMBOL(___strtok);
 EXPORT_SYMBOL(init_special_inode);
 EXPORT_SYMBOL(read_ahead);
 EXPORT_SYMBOL(__get_hash_table);
-EXPORT_SYMBOL(get_empty_inode);
+EXPORT_SYMBOL(new_inode);
 EXPORT_SYMBOL(insert_inode_hash);
 EXPORT_SYMBOL(remove_inode_hash);
-EXPORT_SYMBOL(buffer_insert_inode_queue);
+EXPORT_SYMBOL(buffer_insert_list);
 EXPORT_SYMBOL(make_bad_inode);
 EXPORT_SYMBOL(is_bad_inode);
 EXPORT_SYMBOL(event);
diff -u --recursive --new-file v2.5.2/linux/kernel/printk.c linux/kernel/printk.c
--- v2.5.2/linux/kernel/printk.c	Mon Jan 14 18:25:11 2002
+++ linux/kernel/printk.c	Tue Jan 15 13:53:51 2002
@@ -524,7 +524,7 @@
  */
 void console_conditional_schedule(void)
 {
-	if (console_may_schedule && current->need_resched) {
+	if (console_may_schedule && need_resched()) {
 		set_current_state(TASK_RUNNING);
 		schedule();
 	}
diff -u --recursive --new-file v2.5.2/linux/kernel/sched.c linux/kernel/sched.c
--- v2.5.2/linux/kernel/sched.c	Mon Jan 14 18:25:11 2002
+++ linux/kernel/sched.c	Tue Jan 15 14:33:55 2002
@@ -20,10 +20,7 @@
 #include <linux/interrupt.h>
 #include <asm/mmu_context.h>
 
-#define BITMAP_SIZE ((MAX_PRIO+7)/8)
-#define PRIO_INTERACTIVE	(MAX_RT_PRIO + (MAX_PRIO - MAX_RT_PRIO) / 4)
-#define TASK_INTERACTIVE(p)	((p)->prio >= MAX_RT_PRIO && (p)->prio <= PRIO_INTERACTIVE)
-#define JSLEEP_TO_PRIO(t)	(((t) * 20) / HZ)
+#define BITMAP_SIZE ((((MAX_PRIO+7)/8)+sizeof(long)-1)/sizeof(long))
 
 typedef struct runqueue runqueue_t;
 
@@ -31,7 +28,7 @@
 	int nr_active;
 	spinlock_t *lock;
 	runqueue_t *rq;
-	char bitmap[BITMAP_SIZE];
+	unsigned long bitmap[BITMAP_SIZE];
 	list_t queue[MAX_PRIO];
 };
 
@@ -40,33 +37,36 @@
  *
  * Locking rule: those places that want to lock multiple runqueues
  * (such as the load balancing or the process migration code), lock
- * acquire operations must be ordered by rq->cpu.
+ * acquire operations must be ordered by the runqueue's cpu id.
  *
  * The RT event id is used to avoid calling into the the RT scheduler
  * if there is a RT task active in an SMP system but there is no
  * RT scheduling activity otherwise.
  */
-static struct runqueue {
-	int cpu;
+struct runqueue {
 	spinlock_t lock;
 	unsigned long nr_running, nr_switches;
 	task_t *curr, *idle;
 	prio_array_t *active, *expired, arrays[2];
-	char __pad [SMP_CACHE_BYTES];
-} runqueues [NR_CPUS] __cacheline_aligned;
+	int prev_nr_running[NR_CPUS];
+} ____cacheline_aligned;
+
+static struct runqueue runqueues[NR_CPUS] __cacheline_aligned;
 
-#define this_rq()		(runqueues + smp_processor_id())
-#define task_rq(p)		(runqueues + (p)->cpu)
 #define cpu_rq(cpu)		(runqueues + (cpu))
-#define cpu_curr(cpu)		(runqueues[(cpu)].curr)
+#define this_rq()		cpu_rq(smp_processor_id())
+#define task_rq(p)		cpu_rq((p)->cpu)
+#define cpu_curr(cpu)		(cpu_rq(cpu)->curr)
+#define rq_cpu(rq)		((rq) - runqueues)
 #define rt_task(p)		((p)->policy != SCHED_OTHER)
 
+
 #define lock_task_rq(rq,p,flags)				\
 do {								\
 repeat_lock_task:						\
 	rq = task_rq(p);					\
 	spin_lock_irqsave(&rq->lock, flags);			\
-	if (unlikely((rq)->cpu != (p)->cpu)) {			\
+	if (unlikely(rq_cpu(rq) != (p)->cpu)) {			\
 		spin_unlock_irqrestore(&rq->lock, flags);	\
 		goto repeat_lock_task;				\
 	}							\
@@ -94,18 +94,56 @@
 	p->array = array;
 }
 
+/*
+ * A task is 'heavily interactive' if it has reached the
+ * bottom 25% of the SCHED_OTHER priority range - in this
+ * case we favor it by reinserting it on the active array,
+ * even after it expired its current timeslice.
+ *
+ * A task can get a priority bonus by being 'somewhat
+ * interactive' - and it will get a priority penalty for
+ * being a CPU hog.
+ *
+ * CPU-hog penalties cannot go more than 5 above the default
+ * priority level. Priority bonus cannot go below the minimum
+ * priority level.
+ */
+#define PRIO_INTERACTIVE (MAX_RT_PRIO + MAX_USER_PRIO/3)
+#define TASK_INTERACTIVE(p) ((p)->prio <= PRIO_INTERACTIVE)
+
+static inline int effective_prio(task_t *p)
+{
+	int bonus, prio;
+
+	/*
+	 * Here we scale the actual sleep average [0 .... MAX_SLEEP_AVG]
+	 * into the 20 ... -20 bonus/penalty range.
+	 */
+	bonus = MAX_USER_PRIO * p->sleep_avg / MAX_SLEEP_AVG - MAX_USER_PRIO/2;
+	prio = NICE_TO_PRIO(p->__nice) - bonus;
+	if (prio < MAX_RT_PRIO)
+		prio = MAX_RT_PRIO;
+	if (prio > MAX_PRIO-1)
+		prio = MAX_PRIO-1;
+	return prio;
+}
+
 static inline void activate_task(task_t *p, runqueue_t *rq)
 {
 	prio_array_t *array = rq->active;
 
 	if (!rt_task(p)) {
-		unsigned long prio_bonus = JSLEEP_TO_PRIO(jiffies - p->sleep_jtime);
-
-		if (prio_bonus > MAX_PRIO)
-			prio_bonus = MAX_PRIO;
-		p->prio -= prio_bonus;
-		if (p->prio < MAX_RT_PRIO)
-			p->prio = MAX_RT_PRIO;
+		/*
+		 * This code gives a bonus to interactive tasks. We update
+		 * an 'average sleep time' value here, based on
+		 * sleep_timestamp. The more time a task spends sleeping,
+		 * the higher the average gets - and the higher the priority
+		 * boost gets as well.
+		 */
+		p->sleep_avg += jiffies - p->sleep_timestamp;
+		if (p->sleep_avg > MAX_SLEEP_AVG)
+			p->sleep_avg = MAX_SLEEP_AVG;
+		p->prio = effective_prio(p);
 	}
 	enqueue_task(p, array);
 	rq->nr_running++;
@@ -116,7 +154,7 @@
 	rq->nr_running--;
 	dequeue_task(p, p->array);
 	p->array = NULL;
-	p->sleep_jtime = jiffies;
+	p->sleep_timestamp = jiffies;
 }
 
 static inline void resched_task(task_t *p)
@@ -126,7 +164,7 @@
 	need_resched = p->need_resched;
 	wmb();
 	p->need_resched = 1;
-	if (!need_resched)
+	if (!need_resched && (p->cpu != smp_processor_id()))
 		smp_send_reschedule(p->cpu);
 }
 
@@ -188,17 +226,9 @@
 	lock_task_rq(rq, p, flags);
 	p->state = TASK_RUNNING;
 	if (!p->array) {
-		if (!rt_task(p) && synchronous && (smp_processor_id() < p->cpu)) {
-			spin_lock(&this_rq()->lock);
-			p->cpu = smp_processor_id();
-			activate_task(p, this_rq());
-			spin_unlock(&this_rq()->lock);
-		} else {
-			activate_task(p, rq);
-			if ((rq->curr == rq->idle) ||
-					(p->prio < rq->curr->prio))
-				resched_task(rq->curr);
-		}
+		activate_task(p, rq);
+		if ((rq->curr == rq->idle) || (p->prio < rq->curr->prio))
+			resched_task(rq->curr);
 		success = 1;
 	}
 	unlock_task_rq(rq, p, flags);
@@ -214,13 +244,13 @@
 {
 	runqueue_t *rq = this_rq();
 
-	spin_lock_irq(&rq->lock);
 	p->state = TASK_RUNNING;
 	if (!rt_task(p)) {
 		p->prio += MAX_USER_PRIO/10;
 		if (p->prio > MAX_PRIO-1)
 			p->prio = MAX_PRIO-1;
 	}
+	spin_lock_irq(&rq->lock);
 	activate_task(p, rq);
 	spin_unlock_irq(&rq->lock);
 }
@@ -295,59 +325,98 @@
 }
 
 /*
- * Current runqueue is empty, try to find work on
- * other runqueues.
+ * Current runqueue is empty, or rebalance tick: if there is an
+ * inbalance (current runqueue is too short) then pull from
+ * busiest runqueue(s).
  *
  * We call this with the current runqueue locked,
  * irqs disabled.
  */
-static void load_balance(runqueue_t *this_rq)
+static void load_balance(runqueue_t *this_rq, int idle)
 {
-	int nr_tasks, load, prev_max_load, max_load, idx, i;
+	int imbalance, nr_running, load, prev_max_load,
+		max_load, idx, i, this_cpu = smp_processor_id();
 	task_t *next = this_rq->idle, *tmp;
-	runqueue_t *busiest, *rq_tmp;
+	runqueue_t *busiest, *rq_src;
 	prio_array_t *array;
 	list_t *head, *curr;
 
-	prev_max_load = max_rq_len();
-	nr_tasks = prev_max_load - this_rq->nr_running;
-	/*
-	 * It needs an at least ~10% imbalance to trigger balancing:
-	 */
-	if (nr_tasks <= 1 + prev_max_load/8)
-		return;
-	prev_max_load++;
-
-repeat_search:
 	/*
 	 * We search all runqueues to find the most busy one.
 	 * We do this lockless to reduce cache-bouncing overhead,
-	 * we re-check the source CPU with the lock held.
+	 * we re-check the 'best' source CPU later on again, with
+	 * the lock held.
+	 *
+	 * We fend off statistical fluctuations in runqueue lengths by
+	 * saving the runqueue length during the previous load-balancing
+	 * operation and using the smaller one the current and saved lengths.
+	 * If a runqueue is long enough for a longer amount of time then
+	 * we recognize it and pull tasks from it.
+	 *
+	 * The 'current runqueue length' is a statistical maximum variable,
+	 * for that one we take the longer one - to avoid fluctuations in
+	 * the other direction. So for a load-balance to happen it needs
+	 * stable long runqueue on the target CPU and stable short runqueue
+	 * on the local runqueue.
+	 *
+	 * We make an exception if this CPU is about to become idle - in
+	 * that case we are less picky about moving a task across CPUs and
+	 * take what can be taken.
 	 */
+	if (idle || (this_rq->nr_running > this_rq->prev_nr_running[this_cpu]))
+		nr_running = this_rq->nr_running;
+	else
+		nr_running = this_rq->prev_nr_running[this_cpu];
+	prev_max_load = 1000000000;
+
 	busiest = NULL;
 	max_load = 0;
 	for (i = 0; i < smp_num_cpus; i++) {
-		rq_tmp = cpu_rq(i);
-		load = rq_tmp->nr_running;
+		rq_src = cpu_rq(i);
+		if (idle || (rq_src->nr_running < this_rq->prev_nr_running[i]))
+			load = rq_src->nr_running;
+		else
+			load = this_rq->prev_nr_running[i];
+		this_rq->prev_nr_running[i] = rq_src->nr_running;
+
 		if ((load > max_load) && (load < prev_max_load) &&
-						(rq_tmp != this_rq)) {
-			busiest = rq_tmp;
+						(rq_src != this_rq)) {
+			busiest = rq_src;
 			max_load = load;
 		}
 	}
 
 	if (likely(!busiest))
 		return;
-	if (max_load <= this_rq->nr_running)
+
+	imbalance = (max_load - nr_running) / 2;
+
+	/*
+	 * It needs an at least ~25% imbalance to trigger balancing.
+	 *
+	 * prev_max_load makes sure that we do not try to balance
+	 * ad infinitum - certain tasks might be impossible to be
+	 * pulled into this runqueue.
+	 */
+	if (!idle && (imbalance < (max_load + 3)/4))
 		return;
 	prev_max_load = max_load;
-	if (busiest->cpu < this_rq->cpu) {
+
+	/*
+	 * Ok, lets do some actual balancing:
+	 */
+
+	if (rq_cpu(busiest) < this_cpu) {
 		spin_unlock(&this_rq->lock);
 		spin_lock(&busiest->lock);
 		spin_lock(&this_rq->lock);
 	} else
 		spin_lock(&busiest->lock);
-	if (busiest->nr_running <= this_rq->nr_running + 1)
+	/*
+	 * Make sure nothing changed since we checked the
+	 * runqueue length.
+	 */
+	if (busiest->nr_running <= nr_running + 1)
 		goto out_unlock;
 
 	/*
@@ -373,15 +442,14 @@
 			array = busiest->active;
 			goto new_array;
 		}
-		spin_unlock(&busiest->lock);
-		goto repeat_search;
+		goto out_unlock;
 	}
 
 	head = array->queue + idx;
 	curr = head->next;
 skip_queue:
 	tmp = list_entry(curr, task_t, run_list);
-	if ((tmp == busiest->curr) || !(tmp->cpus_allowed & (1 << smp_processor_id()))) {
+	if ((tmp == busiest->curr) || !(tmp->cpus_allowed & (1 << this_cpu))) {
 		curr = curr->next;
 		if (curr != head)
 			goto skip_queue;
@@ -395,67 +463,96 @@
 	 */
 	dequeue_task(next, array);
 	busiest->nr_running--;
-	next->cpu = smp_processor_id();
+	next->cpu = this_cpu;
 	this_rq->nr_running++;
 	enqueue_task(next, this_rq->active);
 	if (next->prio < current->prio)
 		current->need_resched = 1;
-	if (--nr_tasks) {
+	if (!idle && --imbalance) {
 		if (array == busiest->expired) {
 			array = busiest->active;
 			goto new_array;
 		}
-		spin_unlock(&busiest->lock);
-		goto repeat_search;
 	}
 out_unlock:
 	spin_unlock(&busiest->lock);
 }
 
-/* Rebalance every 250 msecs */
-#define REBALANCE_TICK (HZ/4)
+/*
+ * One of the idle_cpu_tick() or the busy_cpu_tick() function will
+ * gets called every timer tick, on every CPU. Our balancing action
+ * frequency and balancing agressivity depends on whether the CPU is
+ * idle or not.
+ *
+ * busy-rebalance every 250 msecs. idle-rebalance every 1 msec. (or on
+ * systems with HZ=100, every 10 msecs.)
+ */
+#define BUSY_REBALANCE_TICK (HZ/4 ?: 1)
+#define IDLE_REBALANCE_TICK (HZ/1000 ?: 1)
 
-void idle_tick(void)
+static inline void idle_tick(void)
 {
-	unsigned long flags;
-
-	if (!(jiffies % REBALANCE_TICK) && likely(this_rq()->curr != NULL)) {
-		spin_lock_irqsave(&this_rq()->lock, flags);
-		load_balance(this_rq());
-		spin_unlock_irqrestore(&this_rq()->lock, flags);
-	}
+	if ((jiffies % IDLE_REBALANCE_TICK) ||
+			likely(this_rq()->curr == NULL))
+		return;
+	spin_lock(&this_rq()->lock);
+	load_balance(this_rq(), 1);
+	spin_unlock(&this_rq()->lock);
 }
 
-void expire_task(task_t *p)
+/*
+ * This function gets called by the timer code, with HZ frequency.
+ * We call it with interrupts disabled.
+ */
+void scheduler_tick(task_t *p)
 {
+	unsigned long now = jiffies;
 	runqueue_t *rq = this_rq();
-	unsigned long flags;
 
+	if (p == rq->idle || !rq->idle)
+		return idle_tick();
+	/* Task might have expired already, but not scheduled off yet */
 	if (p->array != rq->active) {
 		p->need_resched = 1;
 		return;
 	}
+	spin_lock(&rq->lock);
+	if (unlikely(rt_task(p))) {
+		/*
+		 * RR tasks need a special form of timeslice management.
+		 * FIFO tasks have no timeslices.
+		 */
+		if ((p->policy == SCHED_RR) && !--p->time_slice) {
+			p->time_slice = NICE_TO_TIMESLICE(p->__nice);
+			p->need_resched = 1;
+
+			/* put it at the end of the queue: */
+			dequeue_task(p, rq->active);
+			enqueue_task(p, rq->active);
+		}
+		goto out;
+	}
 	/*
-	 * The task cannot change CPUs because it's the current task.
+	 * The task was running during this tick - update the
+	 * time slice counter and the sleep average. Note: we
+	 * do not update a process's priority until it either
+	 * goes to sleep or uses up its timeslice. This makes
+	 * it possible for interactive tasks to use up their
+	 * timeslices at their high priority levels.
 	 */
-	spin_lock_irqsave(&rq->lock, flags);
-	if ((p->policy != SCHED_FIFO) && !--p->time_slice) {
-		unsigned int time_slice;
-		p->need_resched = 1;
+	if (p->sleep_avg)
+		p->sleep_avg--;
+	if (!--p->time_slice) {
 		dequeue_task(p, rq->active);
-		time_slice = RT_PRIO_TO_TIMESLICE(p->prio);
-		if (!rt_task(p)) {
-			time_slice = PRIO_TO_TIMESLICE(p->prio);
-			if (++p->prio >= MAX_PRIO)
-				p->prio = MAX_PRIO - 1;
-		}
-		p->time_slice = time_slice;
-		if (TASK_INTERACTIVE(p))
-			enqueue_task(p, rq->active);
-		else
-			enqueue_task(p, rq->expired);
-	}
-	spin_unlock_irqrestore(&rq->lock, flags);
+		p->need_resched = 1;
+		p->prio = effective_prio(p);
+		p->time_slice = NICE_TO_TIMESLICE(p->__nice);
+		enqueue_task(p, TASK_INTERACTIVE(p) ? rq->active : rq->expired);
+	}
+out:
+	if (!(now % BUSY_REBALANCE_TICK))
+		load_balance(rq, 0);
+	spin_unlock(&rq->lock);
 }
 
 void scheduling_functions_start_here(void) { }
@@ -480,18 +577,18 @@
 	spin_lock_irq(&rq->lock);
 
 	switch (prev->state) {
-	case TASK_INTERRUPTIBLE:
-		if (unlikely(signal_pending(prev))) {
-			prev->state = TASK_RUNNING;
-			break;
-		}
-	default:
-		deactivate_task(prev, rq);
-	case TASK_RUNNING:
+		case TASK_INTERRUPTIBLE:
+			if (unlikely(signal_pending(prev))) {
+				prev->state = TASK_RUNNING;
+				break;
+			}
+		default:
+			deactivate_task(prev, rq);
+		case TASK_RUNNING:
 	}
 pick_next_task:
 	if (unlikely(!rq->nr_running)) {
-		load_balance(rq);
+		load_balance(rq, 1);
 		if (rq->nr_running)
 			goto pick_next_task;
 		next = rq->idle;
@@ -531,7 +628,7 @@
 	spin_unlock_irq(&rq->lock);
 
 	reacquire_kernel_lock(current);
-	if (unlikely(current->need_resched))
+	if (need_resched())
 		goto need_resched_back;
 	return;
 }
@@ -690,6 +787,8 @@
 	int target_cpu;
 
 	new_mask &= cpu_online_map;
+	if (!new_mask)
+		BUG();
 	p->cpus_allowed = new_mask;
 	/*
 	 * Can the task run on the current CPU? If not then
@@ -703,8 +802,8 @@
 		spin_lock_irq(&target_rq->lock);
 		spin_lock(&this_rq->lock);
 	} else {
-		spin_lock_irq(&target_rq->lock);
-		spin_lock(&this_rq->lock);
+		spin_lock_irq(&this_rq->lock);
+		spin_lock(&target_rq->lock);
 	}
 	dequeue_task(p, p->array);
 	this_rq->nr_running--;
@@ -861,7 +960,7 @@
 		goto out_unlock;
 
 	retval = -EPERM;
-	if ((policy == SCHED_FIFO || policy == SCHED_RR) && 
+	if ((policy == SCHED_FIFO || policy == SCHED_RR) &&
 	    !capable(CAP_SYS_NICE))
 		goto out_unlock;
 	if ((current->euid != p->euid) && (current->euid != p->uid) &&
@@ -890,7 +989,7 @@
 	return retval;
 }
 
-asmlinkage long sys_sched_setscheduler(pid_t pid, int policy, 
+asmlinkage long sys_sched_setscheduler(pid_t pid, int policy,
 				      struct sched_param *param)
 {
 	return setscheduler(pid, policy, param);
@@ -1024,7 +1123,7 @@
 	p = find_process_by_pid(pid);
 	if (p)
 		jiffies_to_timespec(p->policy & SCHED_FIFO ?
-					 0 : RT_PRIO_TO_TIMESLICE(p->prio), &t);
+					 0 : NICE_TO_TIMESLICE(p->prio), &t);
 	read_unlock(&tasklist_lock);
 	if (p)
 		retval = copy_to_user(interval, &t, sizeof(t)) ? -EFAULT : 0;
@@ -1132,7 +1231,7 @@
 	if (rq1 == rq2)
 		spin_lock(&rq1->lock);
 	else {
-		if (rq1->cpu < rq2->cpu) {
+		if (rq_cpu(rq1) < rq_cpu(rq2)) {
 			spin_lock(&rq1->lock);
 			spin_lock(&rq2->lock);
 		} else {
@@ -1161,7 +1260,7 @@
 	this_rq->curr = this_rq->idle = current;
 	deactivate_task(current, rq);
 	current->array = NULL;
-	current->prio = MAX_PRIO;
+	current->prio = MAX_PRIO-1;
 	current->state = TASK_RUNNING;
 	clear_bit(smp_processor_id(), &wait_init_idle);
 	double_rq_unlock(this_rq, rq);
@@ -1190,17 +1289,17 @@
 		rq->active = rq->arrays + 0;
 		rq->expired = rq->arrays + 1;
 		spin_lock_init(&rq->lock);
-		rq->cpu = i;
 
 		for (j = 0; j < 2; j++) {
 			array = rq->arrays + j;
 			array->rq = rq;
 			array->lock = &rq->lock;
-			for (k = 0; k < MAX_PRIO; k++)
+			for (k = 0; k < MAX_PRIO; k++) {
 				INIT_LIST_HEAD(array->queue + k);
-			memset(array->bitmap, 0xff, BITMAP_SIZE);
+				__set_bit(k, array->bitmap);
+			}
 			// zero delimiter for bitsearch
-			clear_bit(MAX_PRIO, array->bitmap);
+			__clear_bit(MAX_PRIO, array->bitmap);
 		}
 	}
 	/*
@@ -1211,9 +1310,6 @@
 	rq->curr = current;
 	rq->idle = NULL;
 	wake_up_process(current);
-
-	for (i = 0; i < PIDHASH_SZ; i++)
-		pidhash[i] = NULL;
 
 	init_timervecs();
 	init_bh(TIMER_BH, timer_bh);
diff -u --recursive --new-file v2.5.2/linux/kernel/softirq.c linux/kernel/softirq.c
--- v2.5.2/linux/kernel/softirq.c	Mon Jan 14 18:25:11 2002
+++ linux/kernel/softirq.c	Tue Jan 15 13:53:51 2002
@@ -387,8 +387,7 @@
 
 		while (softirq_pending(cpu)) {
 			do_softirq();
-			if (current->need_resched)
-				schedule();
+			cond_resched();
 		}
 
 		__set_current_state(TASK_INTERRUPTIBLE);
diff -u --recursive --new-file v2.5.2/linux/kernel/timer.c linux/kernel/timer.c
--- v2.5.2/linux/kernel/timer.c	Mon Jan 14 18:25:11 2002
+++ linux/kernel/timer.c	Tue Jan 15 14:33:55 2002
@@ -585,17 +585,16 @@
 
 	update_one_process(p, user_tick, system, cpu);
 	if (p->pid) {
-		expire_task(p);
 		if (p->__nice > 0)
 			kstat.per_cpu_nice[cpu] += user_tick;
 		else
 			kstat.per_cpu_user[cpu] += user_tick;
 		kstat.per_cpu_system[cpu] += system;
 	} else {
-		idle_tick();
 		if (local_bh_count(cpu) || local_irq_count(cpu) > 1)
 			kstat.per_cpu_system[cpu] += system;
 	}
+	scheduler_tick(p);
 }
 
 /*
diff -u --recursive --new-file v2.5.2/linux/lib/crc32.c linux/lib/crc32.c
--- v2.5.2/linux/lib/crc32.c	Mon Jan 14 18:25:11 2002
+++ linux/lib/crc32.c	Tue Jan 15 11:08:05 2002
@@ -558,7 +558,7 @@
 /**
  * cleanup_crc32(): frees crc32 data when no longer needed
  */
-static void cleanup_crc32(void)
+static void __exit cleanup_crc32(void)
 {
 	crc32cleanup_le();
 	crc32cleanup_be();
diff -u --recursive --new-file v2.5.2/linux/lib/vsprintf.c linux/lib/vsprintf.c
--- v2.5.2/linux/lib/vsprintf.c	Thu Oct 11 11:17:22 2001
+++ linux/lib/vsprintf.c	Tue Jan 15 11:05:25 2002
@@ -616,8 +616,9 @@
 		case 'X':
 			base = 16;
 			break;
-		case 'd':
 		case 'i':
+                        base = 0;
+		case 'd':
 			is_sign = 1;
 		case 'u':
 			break;
@@ -637,7 +638,11 @@
 		while (isspace(*str))
 			str++;
 
-		if (!*str || !isdigit(*str))
+		if (!*str
+                    || (base == 16 && !isxdigit(*str))
+                    || (base == 10 && !isdigit(*str))
+                    || (base == 8 && (!isdigit(*str) || *str > '7'))
+                    || (base == 0 && !isdigit(*str)))
 			break;
 
 		switch(qualifier) {
diff -u --recursive --new-file v2.5.2/linux/mm/filemap.c linux/mm/filemap.c
--- v2.5.2/linux/mm/filemap.c	Mon Jan 14 18:25:11 2002
+++ linux/mm/filemap.c	Tue Jan 15 13:53:51 2002
@@ -290,7 +290,7 @@
 
 			page_cache_release(page);
 
-			if (current->need_resched) {
+			if (need_resched()) {
 				__set_current_state(TASK_RUNNING);
 				schedule();
 			}
@@ -400,7 +400,7 @@
 		}
 
 		page_cache_release(page);
-		if (current->need_resched) {
+		if (need_resched()) {
 			__set_current_state(TASK_RUNNING);
 			schedule();
 		}
@@ -2094,7 +2094,7 @@
 	spin_lock(&vma->vm_mm->page_table_lock);
 
 	dir = pgd_offset(vma->vm_mm, address);
-	flush_cache_range(vma->vm_mm, end - size, end);
+	flush_cache_range(vma, end - size, end);
 	if (address >= end)
 		BUG();
 	do {
@@ -2102,7 +2102,7 @@
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	} while (address && (address < end));
-	flush_tlb_range(vma->vm_mm, end - size, end);
+	flush_tlb_range(vma, end - size, end);
 
 	spin_unlock(&vma->vm_mm->page_table_lock);
 
@@ -2436,7 +2436,7 @@
 	if (vma->vm_flags & VM_LOCKED)
 		return -EINVAL;
 
-	zap_page_range(vma->vm_mm, start, end - start);
+	zap_page_range(vma, start, end - start);
 	return 0;
 }
 
diff -u --recursive --new-file v2.5.2/linux/mm/highmem.c linux/mm/highmem.c
--- v2.5.2/linux/mm/highmem.c	Mon Jan 14 18:25:11 2002
+++ linux/mm/highmem.c	Thu Jan 17 13:59:33 2002
@@ -367,12 +367,6 @@
 		if (pfn >= blk_max_pfn)
 			return;
 
-#ifndef CONFIG_HIGHMEM
-		/*
-		 * should not hit for non-highmem case
-		 */
-		BUG();
-#endif
 		bio_gfp = GFP_NOHIGHIO;
 		pool = page_pool;
 	} else {
diff -u --recursive --new-file v2.5.2/linux/mm/memory.c linux/mm/memory.c
--- v2.5.2/linux/mm/memory.c	Mon Jan 14 18:25:11 2002
+++ linux/mm/memory.c	Tue Jan 15 10:56:36 2002
@@ -355,8 +355,9 @@
 /*
  * remove user pages in a given range.
  */
-void zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long size)
+void zap_page_range(struct vm_area_struct *vma, unsigned long address, unsigned long size)
 {
+	struct mm_struct *mm = vma->vm_mm;
 	mmu_gather_t *tlb;
 	pgd_t * dir;
 	unsigned long start = address, end = address + size;
@@ -374,8 +375,8 @@
 	if (address >= end)
 		BUG();
 	spin_lock(&mm->page_table_lock);
-	flush_cache_range(mm, address, end);
-	tlb = tlb_gather_mmu(mm);
+	flush_cache_range(vma, address, end);
+	tlb = tlb_gather_mmu(vma);
 
 	do {
 		freed += zap_pmd_range(tlb, dir, address, end - address);
@@ -757,16 +758,16 @@
 	return 0;
 }
 
-int zeromap_page_range(unsigned long address, unsigned long size, pgprot_t prot)
+int zeromap_page_range(struct vm_area_struct *vma, unsigned long address, unsigned long size, pgprot_t prot)
 {
 	int error = 0;
 	pgd_t * dir;
 	unsigned long beg = address;
 	unsigned long end = address + size;
-	struct mm_struct *mm = current->mm;
+	struct mm_struct *mm = vma->vm_mm;
 
 	dir = pgd_offset(mm, address);
-	flush_cache_range(mm, beg, end);
+	flush_cache_range(vma, beg, end);
 	if (address >= end)
 		BUG();
 
@@ -783,7 +784,7 @@
 		dir++;
 	} while (address && (address < end));
 	spin_unlock(&mm->page_table_lock);
-	flush_tlb_range(mm, beg, end);
+	flush_tlb_range(vma, beg, end);
 	return error;
 }
 
@@ -838,17 +839,17 @@
 }
 
 /*  Note: this is only safe if the mm semaphore is held when called. */
-int remap_page_range(unsigned long from, unsigned long phys_addr, unsigned long size, pgprot_t prot)
+int remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long phys_addr, unsigned long size, pgprot_t prot)
 {
 	int error = 0;
 	pgd_t * dir;
 	unsigned long beg = from;
 	unsigned long end = from + size;
-	struct mm_struct *mm = current->mm;
+	struct mm_struct *mm = vma->vm_mm;
 
 	phys_addr -= from;
 	dir = pgd_offset(mm, from);
-	flush_cache_range(mm, beg, end);
+	flush_cache_range(vma, beg, end);
 	if (from >= end)
 		BUG();
 
@@ -865,7 +866,7 @@
 		dir++;
 	} while (from && (from < end));
 	spin_unlock(&mm->page_table_lock);
-	flush_tlb_range(mm, beg, end);
+	flush_tlb_range(vma, beg, end);
 	return error;
 }
 
@@ -976,7 +977,6 @@
 static void vmtruncate_list(struct vm_area_struct *mpnt, unsigned long pgoff)
 {
 	do {
-		struct mm_struct *mm = mpnt->vm_mm;
 		unsigned long start = mpnt->vm_start;
 		unsigned long end = mpnt->vm_end;
 		unsigned long len = end - start;
@@ -984,7 +984,7 @@
 
 		/* mapping wholly truncated? */
 		if (mpnt->vm_pgoff >= pgoff) {
-			zap_page_range(mm, start, len);
+			zap_page_range(mpnt, start, len);
 			continue;
 		}
 
@@ -997,7 +997,7 @@
 		/* Ok, partially affected.. */
 		start += diff << PAGE_SHIFT;
 		len = (len - diff) << PAGE_SHIFT;
-		zap_page_range(mm, start, len);
+		zap_page_range(mpnt, start, len);
 	} while ((mpnt = mpnt->vm_next_share) != NULL);
 }
 
@@ -1238,7 +1238,7 @@
 			page_cache_release(new_page);
 			return -1;
 		}
-		copy_highpage(page, new_page);
+		copy_user_highpage(page, new_page, address);
 		page_cache_release(new_page);
 		lru_cache_add(page);
 		new_page = page;
diff -u --recursive --new-file v2.5.2/linux/mm/mmap.c linux/mm/mmap.c
--- v2.5.2/linux/mm/mmap.c	Sun Nov  4 10:17:20 2001
+++ linux/mm/mmap.c	Tue Jan 15 10:56:36 2002
@@ -569,7 +569,7 @@
 	fput(file);
 
 	/* Undo any partial mapping done by a device driver. */
-	zap_page_range(mm, vma->vm_start, vma->vm_end - vma->vm_start);
+	zap_page_range(vma, vma->vm_start, vma->vm_end - vma->vm_start);
 free_vma:
 	kmem_cache_free(vm_area_cachep, vma);
 	return error;
@@ -967,7 +967,7 @@
 		remove_shared_vm_struct(mpnt);
 		mm->map_count--;
 
-		zap_page_range(mm, st, size);
+		zap_page_range(mpnt, st, size);
 
 		/*
 		 * Fix the mapping, and free the old area if it wasn't reused.
@@ -1127,7 +1127,7 @@
 		}
 		mm->map_count--;
 		remove_shared_vm_struct(mpnt);
-		zap_page_range(mm, start, size);
+		zap_page_range(mpnt, start, size);
 		if (mpnt->vm_file)
 			fput(mpnt->vm_file);
 		kmem_cache_free(vm_area_cachep, mpnt);
diff -u --recursive --new-file v2.5.2/linux/mm/mprotect.c linux/mm/mprotect.c
--- v2.5.2/linux/mm/mprotect.c	Mon Jan 14 18:25:11 2002
+++ linux/mm/mprotect.c	Tue Jan 15 10:56:36 2002
@@ -72,13 +72,13 @@
 	} while (address && (address < end));
 }
 
-static void change_protection(unsigned long start, unsigned long end, pgprot_t newprot)
+static void change_protection(struct vm_area_struct *vma, unsigned long start, unsigned long end, pgprot_t newprot)
 {
 	pgd_t *dir;
 	unsigned long beg = start;
 
 	dir = pgd_offset(current->mm, start);
-	flush_cache_range(current->mm, beg, end);
+	flush_cache_range(vma, beg, end);
 	if (start >= end)
 		BUG();
 	spin_lock(&current->mm->page_table_lock);
@@ -88,7 +88,7 @@
 		dir++;
 	} while (start && (start < end));
 	spin_unlock(&current->mm->page_table_lock);
-	flush_tlb_range(current->mm, beg, end);
+	flush_tlb_range(vma, beg, end);
 	return;
 }
 
@@ -261,7 +261,7 @@
 	if (error)
 		return error;
 
-	change_protection(start, end, newprot);
+	change_protection(vma, start, end, newprot);
 	return 0;
 }
 
diff -u --recursive --new-file v2.5.2/linux/mm/mremap.c linux/mm/mremap.c
--- v2.5.2/linux/mm/mremap.c	Mon Jan 14 18:25:11 2002
+++ linux/mm/mremap.c	Tue Jan 15 10:56:36 2002
@@ -88,12 +88,13 @@
 	return error;
 }
 
-static int move_page_tables(struct mm_struct * mm,
+static int move_page_tables(struct vm_area_struct *vma,
 	unsigned long new_addr, unsigned long old_addr, unsigned long len)
 {
+	struct mm_struct *mm = vma->vm_mm;
 	unsigned long offset = len;
 
-	flush_cache_range(mm, old_addr, old_addr + len);
+	flush_cache_range(vma, old_addr, old_addr + len);
 
 	/*
 	 * This is not the clever way to do this, but we're taking the
@@ -105,7 +106,7 @@
 		if (move_one_page(mm, old_addr + offset, new_addr + offset))
 			goto oops_we_failed;
 	}
-	flush_tlb_range(mm, old_addr, old_addr + len);
+	flush_tlb_range(vma, old_addr, old_addr + len);
 	return 0;
 
 	/*
@@ -116,10 +117,10 @@
 	 * the old page tables)
 	 */
 oops_we_failed:
-	flush_cache_range(mm, new_addr, new_addr + len);
+	flush_cache_range(vma, new_addr, new_addr + len);
 	while ((offset += PAGE_SIZE) < len)
 		move_one_page(mm, new_addr + offset, old_addr + offset);
-	zap_page_range(mm, new_addr, len);
+	zap_page_range(vma, new_addr, len);
 	return -1;
 }
 
@@ -177,7 +178,7 @@
 		allocated_vma = 1;
 	}
 
-	if (!move_page_tables(current->mm, new_addr, addr, old_len)) {
+	if (!move_page_tables(vma, new_addr, addr, old_len)) {
 		if (allocated_vma) {
 			*new_vma = *vma;
 			new_vma->vm_start = new_addr;
diff -u --recursive --new-file v2.5.2/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.5.2/linux/mm/swapfile.c	Mon Jan 14 18:25:11 2002
+++ linux/mm/swapfile.c	Tue Jan 15 13:53:51 2002
@@ -696,7 +696,7 @@
 		 * interactive performance.  Interruptible check on
 		 * signal_pending() would be nice, but changes the spec?
 		 */
-		if (current->need_resched)
+		if (need_resched())
 			schedule();
 	}
 
@@ -904,11 +904,12 @@
 	swap_file = filp_open(name, O_RDWR, 0);
 	putname(name);
 	error = PTR_ERR(swap_file);
-	if (error)
+	if (IS_ERR(swap_file))
 		goto bad_swap_2;
 
 	p->swap_file = swap_file;
 
+	error = -EINVAL;
 	if (S_ISBLK(swap_file->f_dentry->d_inode->i_mode)) {
 		p->swap_device = swap_file->f_dentry->d_inode->i_rdev;
 		set_blocksize(p->swap_device, PAGE_SIZE);
diff -u --recursive --new-file v2.5.2/linux/mm/vmscan.c linux/mm/vmscan.c
--- v2.5.2/linux/mm/vmscan.c	Mon Jan 14 18:25:11 2002
+++ linux/mm/vmscan.c	Tue Jan 15 13:53:51 2002
@@ -300,7 +300,7 @@
 
 	counter = mmlist_nr;
 	do {
-		if (unlikely(current->need_resched)) {
+		if (need_resched()) {
 			__set_current_state(TASK_RUNNING);
 			schedule();
 		}
@@ -345,7 +345,7 @@
 	while (--max_scan >= 0 && (entry = inactive_list.prev) != &inactive_list) {
 		struct page * page;
 
-		if (unlikely(current->need_resched)) {
+		if (need_resched()) {
 			spin_unlock(&pagemap_lru_lock);
 			__set_current_state(TASK_RUNNING);
 			schedule();
@@ -625,8 +625,7 @@
 
 	for (i = pgdat->nr_zones-1; i >= 0; i--) {
 		zone = pgdat->node_zones + i;
-		if (unlikely(current->need_resched))
-			schedule();
+		cond_resched();
 		if (!zone->need_balance)
 			continue;
 		if (!try_to_free_pages(zone, GFP_KSWAPD, 0)) {
diff -u --recursive --new-file v2.5.2/linux/net/Config.in linux/net/Config.in
--- v2.5.2/linux/net/Config.in	Mon Jan 14 18:25:11 2002
+++ linux/net/Config.in	Tue Jan 15 10:56:35 2002
@@ -7,11 +7,9 @@
 if [ "$CONFIG_PACKET" != "n" ]; then
    bool '  Packet socket: mmapped IO' CONFIG_PACKET_MMAP
 fi
-bool 'Kernel/User netlink socket' CONFIG_NETLINK
-if [ "$CONFIG_NETLINK" = "y" ]; then
-   bool '  Routing messages' CONFIG_RTNETLINK
-   tristate '  Netlink device emulation' CONFIG_NETLINK_DEV
-fi
+
+tristate 'Netlink device emulation' CONFIG_NETLINK_DEV
+
 bool 'Network packet filtering (replaces ipchains)' CONFIG_NETFILTER
 if [ "$CONFIG_NETFILTER" = "y" ]; then
    bool '  Network packet filtering debugging' CONFIG_NETFILTER_DEBUG
diff -u --recursive --new-file v2.5.2/linux/net/Makefile linux/net/Makefile
--- v2.5.2/linux/net/Makefile	Tue Oct 30 15:08:12 2001
+++ linux/net/Makefile	Tue Jan 15 10:56:35 2002
@@ -14,7 +14,7 @@
 subdir-m :=	ipv4 # hum?
 
 
-subdir-$(CONFIG_NET)		+= 802 sched
+subdir-$(CONFIG_NET)		+= 802 sched netlink
 subdir-$(CONFIG_INET)		+= ipv4
 subdir-$(CONFIG_NETFILTER)	+= ipv4/netfilter
 subdir-$(CONFIG_UNIX)		+= unix
@@ -27,7 +27,6 @@
 endif
 
 subdir-$(CONFIG_KHTTPD)		+= khttpd
-subdir-$(CONFIG_NETLINK)	+= netlink
 subdir-$(CONFIG_PACKET)		+= packet
 subdir-$(CONFIG_NET_SCHED)	+= sched
 subdir-$(CONFIG_BRIDGE)		+= bridge
diff -u --recursive --new-file v2.5.2/linux/net/core/datagram.c linux/net/core/datagram.c
--- v2.5.2/linux/net/core/datagram.c	Thu Apr 12 12:11:39 2001
+++ linux/net/core/datagram.c	Tue Jan 15 10:56:35 2002
@@ -30,21 +30,18 @@
 #include <asm/system.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
-#include <linux/in.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/inet.h>
 #include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
 #include <linux/poll.h>
 #include <linux/highmem.h>
 
-#include <net/ip.h>
 #include <net/protocol.h>
-#include <net/route.h>
-#include <net/tcp.h>
-#include <net/udp.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
+#include <net/checksum.h>
 
 
 /*
diff -u --recursive --new-file v2.5.2/linux/net/core/neighbour.c linux/net/core/neighbour.c
--- v2.5.2/linux/net/core/neighbour.c	Mon Oct  1 09:19:56 2001
+++ linux/net/core/neighbour.c	Tue Jan 15 10:56:35 2002
@@ -1172,9 +1172,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_RTNETLINK
-
-
 int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
 	struct ndmsg *ndm = NLMSG_DATA(nlh);
@@ -1438,12 +1435,7 @@
 	netlink_broadcast(rtnl, skb, 0, RTMGRP_NEIGH, GFP_ATOMIC);
 }
 
-
-
-#endif
-
-
-#endif
+#endif /* CONFIG_ARPD */
 
 #ifdef CONFIG_SYSCTL
 
diff -u --recursive --new-file v2.5.2/linux/net/core/rtnetlink.c linux/net/core/rtnetlink.c
--- v2.5.2/linux/net/core/rtnetlink.c	Sun Aug  5 13:12:41 2001
+++ linux/net/core/rtnetlink.c	Tue Jan 15 10:56:35 2002
@@ -45,7 +45,6 @@
 #include <net/protocol.h>
 #include <net/arp.h>
 #include <net/route.h>
-#include <net/tcp.h>
 #include <net/udp.h>
 #include <net/sock.h>
 #include <net/pkt_sched.h>
@@ -77,15 +76,10 @@
 	return 0;
 }
 
-#ifdef CONFIG_RTNETLINK
 struct sock *rtnl;
 
 struct rtnetlink_link * rtnetlink_links[NPROTO];
 
-#define _S	1	/* superuser privileges required */
-#define _X	2	/* exclusive access to tables required */
-#define _G	4	/* GET request */
-
 static const int rtm_min[(RTM_MAX+1-RTM_BASE)/4] =
 {
 	NLMSG_LENGTH(sizeof(struct ifinfomsg)),
@@ -533,7 +527,3 @@
 	rtnetlink_links[PF_UNSPEC] = link_rtnetlink_table;
 	rtnetlink_links[PF_PACKET] = link_rtnetlink_table;
 }
-
-
-
-#endif
diff -u --recursive --new-file v2.5.2/linux/net/core/scm.c linux/net/core/scm.c
--- v2.5.2/linux/net/core/scm.c	Thu Nov  9 15:57:53 2000
+++ linux/net/core/scm.c	Tue Jan 15 10:56:35 2002
@@ -26,11 +26,7 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
-#include <linux/inet.h>
-#include <net/ip.h>
 #include <net/protocol.h>
-#include <net/tcp.h>
-#include <net/udp.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <net/scm.h>
diff -u --recursive --new-file v2.5.2/linux/net/core/skbuff.c linux/net/core/skbuff.c
--- v2.5.2/linux/net/core/skbuff.c	Tue Aug  7 08:30:50 2001
+++ linux/net/core/skbuff.c	Tue Jan 15 10:56:35 2002
@@ -4,7 +4,7 @@
  *	Authors:	Alan Cox <iiitac@pyr.swan.ac.uk>
  *			Florian La Roche <rzsfl@rz.uni-sb.de>
  *
- *	Version:	$Id: skbuff.c,v 1.89 2001/08/06 13:25:02 davem Exp $
+ *	Version:	$Id: skbuff.c,v 1.90 2001/11/07 05:56:19 davem Exp $
  *
  *	Fixes:	
  *		Alan Cox	:	Fixed the worst of the load balancer bugs.
@@ -49,15 +49,14 @@
 #include <linux/string.h>
 #include <linux/skbuff.h>
 #include <linux/cache.h>
+#include <linux/rtnetlink.h>
 #include <linux/init.h>
 #include <linux/highmem.h>
 
-#include <net/ip.h>
 #include <net/protocol.h>
 #include <net/dst.h>
-#include <net/tcp.h>
-#include <net/udp.h>
 #include <net/sock.h>
+#include <net/checksum.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
diff -u --recursive --new-file v2.5.2/linux/net/core/sock.c linux/net/core/sock.c
--- v2.5.2/linux/net/core/sock.c	Sat Jul 28 12:12:38 2001
+++ linux/net/core/sock.c	Tue Jan 15 10:56:35 2002
@@ -7,7 +7,7 @@
  *		handler for protocols to use and generic option handler.
  *
  *
- * Version:	$Id: sock.c,v 1.112 2001/07/27 09:54:48 davem Exp $
+ * Version:	$Id: sock.c,v 1.116 2001/11/08 04:20:06 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -113,24 +113,20 @@
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
-#include <linux/inet.h>
 #include <linux/netdevice.h>
-#include <net/ip.h>
 #include <net/protocol.h>
-#include <net/arp.h>
-#include <net/route.h>
-#include <net/tcp.h>
-#include <net/udp.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <net/raw.h>
-#include <net/icmp.h>
 #include <linux/ipsec.h>
 
 #ifdef CONFIG_FILTER
 #include <linux/filter.h>
 #endif
 
+#ifdef CONFIG_INET
+#include <net/tcp.h>
+#endif
+
 /* Run time adjustable parameters. */
 __u32 sysctl_wmem_max = SK_WMEM_MAX;
 __u32 sysctl_rmem_max = SK_RMEM_MAX;
@@ -759,48 +755,62 @@
  *	Generic send/receive buffer handlers
  */
 
-struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, 
-			int noblock, int *errcode)
+struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsigned long header_len,
+				     unsigned long data_len, int noblock, int *errcode)
 {
-	int err;
 	struct sk_buff *skb;
 	long timeo;
+	int err;
 
 	timeo = sock_sndtimeo(sk, noblock);
-
 	while (1) {
-		unsigned long try_size = size;
-
 		err = sock_error(sk);
 		if (err != 0)
 			goto failure;
 
-		/*
-		 *	We should send SIGPIPE in these cases according to
-		 *	1003.1g draft 6.4. If we (the user) did a shutdown()
-		 *	call however we should not. 
-		 *
-		 *	Note: This routine isnt just used for datagrams and
-		 *	anyway some datagram protocols have a notion of
-		 *	close down.
-		 */
-
 		err = -EPIPE;
-		if (sk->shutdown&SEND_SHUTDOWN)
+		if (sk->shutdown & SEND_SHUTDOWN)
 			goto failure;
 
 		if (atomic_read(&sk->wmem_alloc) < sk->sndbuf) {
-			skb = alloc_skb(try_size, sk->allocation);
-			if (skb)
+			skb = alloc_skb(header_len, sk->allocation);
+			if (skb) {
+				int npages;
+				int i;
+
+				/* No pages, we're done... */
+				if (!data_len)
+					break;
+
+				npages = (data_len + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+				skb->truesize += data_len;
+				skb_shinfo(skb)->nr_frags = npages;
+				for (i = 0; i < npages; i++) {
+					struct page *page;
+					skb_frag_t *frag;
+
+					page = alloc_pages(sk->allocation, 0);
+					if (!page) {
+						err = -ENOBUFS;
+						kfree_skb(skb);
+						goto failure;
+					}
+
+					frag = &skb_shinfo(skb)->frags[i];
+					frag->page = page;
+					frag->page_offset = 0;
+					frag->size = (data_len >= PAGE_SIZE ?
+						      PAGE_SIZE :
+						      data_len);
+					data_len -= PAGE_SIZE;
+				}
+
+				/* Full success... */
 				break;
+			}
 			err = -ENOBUFS;
 			goto failure;
 		}
-
-		/*
-		 *	This means we have too many buffers for this socket already.
-		 */
-
 		set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
 		set_bit(SOCK_NOSPACE, &sk->socket->flags);
 		err = -EAGAIN;
@@ -819,6 +829,12 @@
 failure:
 	*errcode = err;
 	return NULL;
+}
+
+struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, 
+				    int noblock, int *errcode)
+{
+	return sock_alloc_send_pskb(sk, size, 0, noblock, errcode);
 }
 
 void __lock_sock(struct sock *sk)
diff -u --recursive --new-file v2.5.2/linux/net/decnet/README linux/net/decnet/README
--- v2.5.2/linux/net/decnet/README	Wed May 26 09:36:36 1999
+++ linux/net/decnet/README	Tue Jan 15 10:56:35 2002
@@ -3,6 +3,6 @@
 
 The documentation for this kernel subsystem is available in the
 Documentation/networking subdirctory of this distribution and also
-on line at http://www.sucs.swan.ac.uk/~rohan/DECnet/index.html.
+on line at http://www.chygwyn.com/DECnet/
 
 Steve Whitehouse <SteveW@ACM.org>
diff -u --recursive --new-file v2.5.2/linux/net/decnet/af_decnet.c linux/net/decnet/af_decnet.c
--- v2.5.2/linux/net/decnet/af_decnet.c	Mon Jan 14 18:25:11 2002
+++ linux/net/decnet/af_decnet.c	Tue Jan 15 10:56:35 2002
@@ -36,6 +36,7 @@
  *        Steve Whitehouse: Removed unused code. Fix to use sk->allocation
  *                          when required.
  *       Patrick Caulfield: /proc/net/decnet now has object name/number
+ *        Steve Whitehouse: Fixed local port allocation, hashed sk list
  */
 
 
@@ -138,9 +139,13 @@
 dn_address decnet_address = 0;
 unsigned char decnet_ether_address[ETH_ALEN] = { 0xAA, 0x00, 0x04, 0x00, 0x00, 0x00 };
 
+#define DN_SK_HASH_SHIFT 8
+#define DN_SK_HASH_SIZE (1 << DN_SK_HASH_SHIFT)
+#define DN_SK_HASH_MASK (DN_SK_HASH_SIZE - 1)
+
 static struct proto_ops dn_proto_ops;
 rwlock_t dn_hash_lock = RW_LOCK_UNLOCKED;
-static struct sock *dn_sklist;
+static struct sock *dn_sk_hash[DN_SK_HASH_SIZE];
 static struct sock *dn_wild_sk;
 
 static int __dn_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen, int flags);
@@ -153,18 +158,38 @@
 	if (scp->addr.sdn_flags & SDF_WILD)
 		return dn_wild_sk ? NULL : &dn_wild_sk;
 
-	return &dn_sklist;
+	return &dn_sk_hash[scp->addrloc & DN_SK_HASH_MASK];
+}
+
+/* 
+ * Valid ports are those greater than zero and not already in use.
+ */
+static int check_port(unsigned short port)
+{
+	struct sock *sk = dn_sk_hash[port & DN_SK_HASH_MASK];
+	if (port == 0)
+		return -1;
+	while(sk) {
+		struct dn_scp *scp = DN_SK(sk);
+		if (scp->addrloc == port)
+			return -1;
+		sk = sk->next;
+	}
+	return 0;
 }
 
 static unsigned short port_alloc(struct sock *sk)
 {
 	struct dn_scp *scp = DN_SK(sk);
 static unsigned short port = 0x2000;
+	unsigned short i_port = port;
 
-	if (port == 0)
-		port++;
+	while(check_port(++port) != 0) {
+		if (port == i_port)
+			return 0;
+	}
 
-	scp->addrloc = port++;
+	scp->addrloc = port;
 
 	return 1;
 }
@@ -237,6 +262,48 @@
 	sk->pprev = NULL;
 }
 
+struct sock **listen_hash(struct sockaddr_dn *addr)
+{
+	int i;
+	unsigned hash = addr->sdn_objnum;
+
+	if (hash == 0) {
+		hash = addr->sdn_objnamel;
+		for(i = 0; i < addr->sdn_objnamel; i++) {
+			hash ^= addr->sdn_objname[i];
+			hash ^= (hash << 3);
+		}
+	}
+
+	return &dn_sk_hash[hash & DN_SK_HASH_MASK];
+}
+
+/*
+ * Called to transform a socket from bound (i.e. with a local address)
+ * into a listening socket (doesn't need a local port number) and rehashes
+ * based upon the object name/number.
+ */
+static void dn_rehash_sock(struct sock *sk)
+{
+	struct sock **skp = sk->pprev;
+	struct dn_scp *scp = DN_SK(sk);
+
+	if (scp->addr.sdn_flags & SDF_WILD)
+		return;
+
+	write_lock_bh(&dn_hash_lock);
+	while(*skp != sk)
+		skp = &((*skp)->next);
+	*skp = sk->next;
+
+	DN_SK(sk)->addrloc = 0;
+	skp = listen_hash(&DN_SK(sk)->addr);
+
+	sk->next = *skp;
+	sk->pprev = skp;
+	*skp = sk;
+	write_unlock_bh(&dn_hash_lock);
+}
 
 int dn_sockaddr2username(struct sockaddr_dn *sdn, unsigned char *buf, unsigned char type)
 {
@@ -327,10 +394,11 @@
 
 struct sock *dn_sklist_find_listener(struct sockaddr_dn *addr)
 {
+	struct sock **skp = listen_hash(addr);
 	struct sock *sk;
 
 	read_lock(&dn_hash_lock);
-	for(sk = dn_sklist; sk != NULL; sk = sk->next) {
+	for(sk = *skp; sk != NULL; sk = sk->next) {
 		struct dn_scp *scp = DN_SK(sk);
 		if (sk->state != TCP_LISTEN)
 			continue;
@@ -364,7 +432,8 @@
 	struct dn_scp *scp;
 
 	read_lock(&dn_hash_lock);
-	for(sk = dn_sklist; sk != NULL; sk = sk->next) {
+	sk = dn_sk_hash[cb->dst_port & DN_SK_HASH_MASK];
+	for (; sk != NULL; sk = sk->next) {
 		scp = DN_SK(sk);
 		if (cb->src != dn_saddr2dn(&scp->peer))
 			continue;
@@ -1044,6 +1113,9 @@
 		sizeof(struct optdata_dn));
 
 	lock_sock(newsk);
+	/*
+	 * FIXME: This can fail if we've run out of local ports....
+	 */
 	dn_hash_sock(newsk);
 
 	dn_send_conn_ack(newsk);
@@ -1199,6 +1271,7 @@
 	sk->ack_backlog     = 0;
 	sk->state           = TCP_LISTEN;
 	err                 = 0;
+	dn_rehash_sock(sk);
 
 out:
 	release_sock(sk);
@@ -2062,44 +2135,47 @@
 	char buf2[DN_ASCBUF_LEN];
 	char local_object[DN_MAXOBJL+3];
 	char remote_object[DN_MAXOBJL+3];
+	int i;
 
 	len += sprintf(buffer + len, "Local                                              Remote\n");
 
 	read_lock(&dn_hash_lock);
-	for(sk = dn_sklist; sk != NULL; sk = sk->next) {
-		scp = DN_SK(sk);
-
-		dn_printable_object(&scp->addr, local_object);
-		dn_printable_object(&scp->peer, remote_object);
-
-		len += sprintf(buffer + len,
-				"%6s/%04X %04d:%04d %04d:%04d %01d %-16s %6s/%04X %04d:%04d %04d:%04d %01d %-16s %4s %s\n",
-				dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->addr)), buf1),
-				scp->addrloc,
-				scp->numdat,
-				scp->numoth,
-				scp->ackxmt_dat,
-				scp->ackxmt_oth,
-				scp->flowloc_sw,
-				local_object,
-				dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->peer)), buf2),
-				scp->addrrem,
-				scp->numdat_rcv,
-				scp->numoth_rcv,
-				scp->ackrcv_dat,
-				scp->ackrcv_oth,
-				scp->flowrem_sw,
-				remote_object,
-				dn_state2asc(scp->state),
-				((scp->accept_mode == ACC_IMMED) ? "IMMED" : "DEFER"));
-
-		pos = begin + len;
-		if (pos < offset) {
-			len = 0;
-			begin = pos;
+	for(i = 0; i < DN_SK_HASH_SIZE; i++) {
+		for(sk = dn_sk_hash[i]; sk != NULL; sk = sk->next) {
+			scp = DN_SK(sk);
+
+			dn_printable_object(&scp->addr, local_object);
+			dn_printable_object(&scp->peer, remote_object);
+
+			len += sprintf(buffer + len,
+					"%6s/%04X %04d:%04d %04d:%04d %01d %-16s %6s/%04X %04d:%04d %04d:%04d %01d %-16s %4s %s\n",
+					dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->addr)), buf1),
+					scp->addrloc,
+					scp->numdat,
+					scp->numoth,
+					scp->ackxmt_dat,
+					scp->ackxmt_oth,
+					scp->flowloc_sw,
+					local_object,
+					dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->peer)), buf2),
+					scp->addrrem,
+					scp->numdat_rcv,
+					scp->numoth_rcv,
+					scp->ackrcv_dat,
+					scp->ackrcv_oth,
+					scp->flowrem_sw,
+					remote_object,
+					dn_state2asc(scp->state),
+					((scp->accept_mode == ACC_IMMED) ? "IMMED" : "DEFER"));
+
+			pos = begin + len;
+			if (pos < offset) {
+				len = 0;
+				begin = pos;
+			}
+			if (pos > (offset + length))
+				break;
 		}
-		if (pos > (offset + length))
-			break;
 	}
 	read_unlock(&dn_hash_lock);
 
@@ -2157,7 +2233,7 @@
 MODULE_PARM_DESC(addr, "The DECnet address of this machine: area,node");
 #endif
 
-static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.4.9s (C) 1995-2001 Linux DECnet Project Team\n";
+static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.4.15-pre5s (C) 1995-2001 Linux DECnet Project Team\n";
 
 static int __init decnet_init(void)
 {
diff -u --recursive --new-file v2.5.2/linux/net/decnet/dn_dev.c linux/net/decnet/dn_dev.c
--- v2.5.2/linux/net/decnet/dn_dev.c	Fri Jul  6 16:46:22 2001
+++ linux/net/decnet/dn_dev.c	Tue Jan 15 10:56:35 2002
@@ -56,9 +56,7 @@
 
 static struct dn_dev *dn_dev_create(struct net_device *dev, int *err);
 static void dn_dev_delete(struct net_device *dev);
-#ifdef CONFIG_RTNETLINK
 static void rtmsg_ifa(int event, struct dn_ifaddr *ifa);
-#endif
 
 static int dn_eth_up(struct net_device *);
 static void dn_send_brd_hello(struct net_device *dev);
@@ -369,9 +367,7 @@
 
 	*ifap = ifa1->ifa_next;
 
-#ifdef CONFIG_RTNETLINK
 	rtmsg_ifa(RTM_DELADDR, ifa1);
-#endif /* CONFIG_RTNETLINK */
 
 	if (destroy) {
 		dn_dev_free_ifa(ifa1);
@@ -390,9 +386,7 @@
 	ifa->ifa_next = dn_db->ifa_list;
 	dn_db->ifa_list = ifa;
 
-#ifdef CONFIG_RTNETLINK
 	rtmsg_ifa(RTM_NEWADDR, ifa);
-#endif /* CONFIG_RTNETLINK */
 
 	return 0;
 }
@@ -501,7 +495,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_RTNETLINK
 static struct dn_dev *dn_dev_by_index(int ifindex)
 {
 	struct net_device *dev;
@@ -658,8 +651,6 @@
 	return skb->len;
 }
 
-#endif /* CONFIG_RTNETLINK */
-
 static void dn_send_endnode_hello(struct net_device *dev)
 {
         struct endnode_hello_message *msg;
@@ -1172,7 +1163,6 @@
 
 #endif /* CONFIG_PROC_FS */
 
-#ifdef CONFIG_RTNETLINK
 static struct rtnetlink_link dnet_rtnetlink_table[RTM_MAX-RTM_BASE+1] = 
 {
 	{ NULL,			NULL,			},
@@ -1213,7 +1203,6 @@
 	{ NULL,			NULL,			}
 #endif
 };
-#endif /* CONFIG_RTNETLINK */
 
 void __init dn_dev_init(void)
 {
@@ -1223,9 +1212,7 @@
 	register_gifconf(PF_DECnet, dnet_gifconf);
 #endif /* CONFIG_DECNET_SIOCGIFCONF */
 
-#ifdef CONFIG_RTNETLINK
 	rtnetlink_links[PF_DECnet] = dnet_rtnetlink_table;
-#endif /* CONFIG_RTNETLINK */
 
 #ifdef CONFIG_PROC_FS
 	proc_net_create("decnet_dev", 0, decnet_dev_get_info);
@@ -1242,9 +1229,7 @@
 
 void __exit dn_dev_cleanup(void)
 {
-#ifdef CONFIG_RTNETLINK
 	rtnetlink_links[PF_DECnet] = NULL;
-#endif /* CONFIG_RTNETLINK */
 
 #ifdef CONFIG_DECNET_SIOCGIFCONF
 	unregister_gifconf(PF_DECnet);
diff -u --recursive --new-file v2.5.2/linux/net/decnet/dn_fib.c linux/net/decnet/dn_fib.c
--- v2.5.2/linux/net/decnet/dn_fib.c	Mon Jan 22 13:32:10 2001
+++ linux/net/decnet/dn_fib.c	Tue Jan 15 10:56:35 2002
@@ -50,9 +50,7 @@
 
 #define endfor_nexthops(fi) }
 
-#ifdef CONFIG_RTNETLINK
 extern int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb);
-#endif /* CONFIG_RTNETLINK */
 
 
 static struct dn_fib_info *dn_fib_info_list;
@@ -415,8 +413,6 @@
 }
 
 
-#ifdef CONFIG_RTNETLINK
-
 static int dn_fib_check_attr(struct rtmsg *r, struct rtattr **rta)
 {
 	int i;
@@ -497,7 +493,6 @@
 
 	return skb->len;
 }
-#endif /* CONFIG_RTNETLINK */
 
 int dn_fib_sync_down(dn_address local, struct net_device *dev, int force)
 {
diff -u --recursive --new-file v2.5.2/linux/net/decnet/dn_route.c linux/net/decnet/dn_route.c
--- v2.5.2/linux/net/decnet/dn_route.c	Fri Nov  9 14:12:54 2001
+++ linux/net/decnet/dn_route.c	Tue Jan 15 10:56:35 2002
@@ -1020,7 +1020,6 @@
 	return dn_route_input_slow(skb);
 }
 
-#ifdef CONFIG_RTNETLINK
 static int dn_rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, int nowait)
 {
 	struct dn_route *rt = (struct dn_route *)skb->dst;
@@ -1181,7 +1180,6 @@
 	cb->args[1] = idx;
 	return skb->len;
 }
-#endif /* CONFIG_RTNETLINK */
 
 #ifdef CONFIG_PROC_FS
 
diff -u --recursive --new-file v2.5.2/linux/net/decnet/dn_rules.c linux/net/decnet/dn_rules.c
--- v2.5.2/linux/net/decnet/dn_rules.c	Mon Jan 22 13:32:10 2001
+++ linux/net/decnet/dn_rules.c	Tue Jan 15 10:56:35 2002
@@ -299,8 +299,6 @@
 	notifier_call:		dn_fib_rules_event,
 };
 
-#ifdef CONFIG_RTNETLINK
-
 static int dn_fib_fill_rule(struct sk_buff *skb, struct dn_fib_rule *r, struct netlink_callback *cb)
 {
 	struct rtmsg *rtm;
@@ -359,8 +357,6 @@
 
 	return skb->len;
 }
-
-#endif /* CONFIG_RTNETLINK */
 
 void __init dn_fib_rules_init(void)
 {
diff -u --recursive --new-file v2.5.2/linux/net/decnet/dn_table.c linux/net/decnet/dn_table.c
--- v2.5.2/linux/net/decnet/dn_table.c	Mon Jan 22 13:32:10 2001
+++ linux/net/decnet/dn_table.c	Tue Jan 15 10:56:35 2002
@@ -267,7 +267,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_RTNETLINK
 static int dn_fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
                         u8 tb_id, u8 type, u8 scope, void *dst, int dst_len,
                         struct dn_fib_info *fi)
@@ -435,12 +434,6 @@
         return skb->len;
 }
 
-#else /* no CONFIG_RTNETLINK */
-
-#define dn_rtmsg_fib(event,f,z,tb_id,nlh,req)
-
-#endif /* CONFIG_RTNETLINK */
-
 static int dn_fib_table_insert(struct dn_fib_table *tb, struct rtmsg *r, struct dn_kern_rta *rta, struct nlmsghdr *n, struct netlink_skb_parms *req)
 {
 	struct dn_hash *table = (struct dn_hash *)tb->data;
@@ -860,9 +853,7 @@
 #ifdef CONFIG_PROC_FS
 	t->get_info = dn_fib_table_get_info;
 #endif
-#ifdef CONFIG_RTNETLINK
         t->dump = dn_fib_table_dump;
-#endif
         dn_fib_tables[n] = t;
 
         return t;
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/Config.in linux/net/ipv4/Config.in
--- v2.5.2/linux/net/ipv4/Config.in	Tue May  1 20:59:24 2001
+++ linux/net/ipv4/Config.in	Tue Jan 15 10:56:35 2002
@@ -4,8 +4,6 @@
 bool '  IP: multicasting' CONFIG_IP_MULTICAST
 bool '  IP: advanced router' CONFIG_IP_ADVANCED_ROUTER
 if [ "$CONFIG_IP_ADVANCED_ROUTER" = "y" ]; then
-   define_bool CONFIG_RTNETLINK y	
-   define_bool CONFIG_NETLINK y
    bool '    IP: policy routing' CONFIG_IP_MULTIPLE_TABLES
    if [ "$CONFIG_IP_MULTIPLE_TABLES" = "y" ]; then
       if [ "$CONFIG_NETFILTER" = "y" ]; then
@@ -39,9 +37,7 @@
    fi
 fi
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   if [ "$CONFIG_RTNETLINK" = "y" ]; then
-      bool '  IP: ARP daemon support (EXPERIMENTAL)' CONFIG_ARPD
-   fi
+   bool '  IP: ARP daemon support (EXPERIMENTAL)' CONFIG_ARPD
 fi
 bool '  IP: TCP Explicit Congestion Notification support' CONFIG_INET_ECN
 bool '  IP: TCP syncookie support (disabled per default)' CONFIG_SYN_COOKIES
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/Makefile linux/net/ipv4/Makefile
--- v2.5.2/linux/net/ipv4/Makefile	Tue Oct 30 15:08:12 2001
+++ linux/net/ipv4/Makefile	Tue Jan 15 10:56:35 2002
@@ -15,7 +15,7 @@
 	     ip_input.o ip_fragment.o ip_forward.o ip_options.o \
 	     ip_output.o ip_sockglue.o \
 	     tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o tcp_minisocks.o \
-	     raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o \
+	     tcp_diag.o raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o \
 	     sysctl_net_ipv4.o fib_frontend.o fib_semantics.o fib_hash.o
 
 obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v2.5.2/linux/net/ipv4/af_inet.c	Mon Nov  5 09:46:12 2001
+++ linux/net/ipv4/af_inet.c	Tue Jan 15 10:56:35 2002
@@ -5,7 +5,7 @@
  *
  *		PF_INET protocol family socket handler.
  *
- * Version:	$Id: af_inet.c,v 1.135 2001/10/27 03:27:13 davem Exp $
+ * Version:	$Id: af_inet.c,v 1.136 2001/11/06 22:21:08 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c
--- v2.5.2/linux/net/ipv4/devinet.c	Mon Oct  1 09:19:57 2001
+++ linux/net/ipv4/devinet.c	Tue Jan 15 10:56:35 2002
@@ -1,7 +1,7 @@
 /*
  *	NET3	IP device support routines.
  *
- *	Version: $Id: devinet.c,v 1.43 2001/09/26 22:52:58 davem Exp $
+ *	Version: $Id: devinet.c,v 1.44 2001/10/31 21:55:54 davem Exp $
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -63,11 +63,7 @@
 struct ipv4_devconf ipv4_devconf = { 1, 1, 1, 1, 0, };
 static struct ipv4_devconf ipv4_devconf_dflt = { 1, 1, 1, 1, 1, };
 
-#ifdef CONFIG_RTNETLINK
 static void rtmsg_ifa(int event, struct in_ifaddr *);
-#else
-#define rtmsg_ifa(a,b)	do { } while(0)
-#endif
 
 static struct notifier_block *inetaddr_chain;
 static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, int destroy);
@@ -359,8 +355,6 @@
 	return NULL;
 }
 
-#ifdef CONFIG_RTNETLINK
-
 int
 inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
@@ -437,8 +431,6 @@
 	return inet_insert_ifa(ifa);
 }
 
-#endif
-
 /* 
  *	Determine a default network mask, based on the IP address. 
  */
@@ -859,8 +851,6 @@
 	notifier_call:	inetdev_event,
 };
 
-#ifdef CONFIG_RTNETLINK
-
 static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
 			    u32 pid, u32 seq, int event)
 {
@@ -994,8 +984,6 @@
 #endif
 };
 
-#endif /* CONFIG_RTNETLINK */
-
 
 #ifdef CONFIG_SYSCTL
 
@@ -1150,9 +1138,7 @@
 {
 	register_gifconf(PF_INET, inet_gifconf);
 	register_netdevice_notifier(&ip_netdev_notifier);
-#ifdef CONFIG_RTNETLINK
 	rtnetlink_links[PF_INET] = inet_rtnetlink_table;
-#endif
 #ifdef CONFIG_SYSCTL
 	devinet_sysctl.sysctl_header =
 		register_sysctl_table(devinet_sysctl.devinet_root_dir, 0);
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/fib_frontend.c linux/net/ipv4/fib_frontend.c
--- v2.5.2/linux/net/ipv4/fib_frontend.c	Mon Jun 11 19:15:27 2001
+++ linux/net/ipv4/fib_frontend.c	Tue Jan 15 10:56:35 2002
@@ -5,7 +5,7 @@
  *
  *		IPv4 Forwarding Information Base: FIB frontend.
  *
- * Version:	$Id: fib_frontend.c,v 1.25 2001/05/29 22:16:25 davem Exp $
+ * Version:	$Id: fib_frontend.c,v 1.26 2001/10/31 21:55:54 davem Exp $
  *
  * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
@@ -332,8 +332,6 @@
 
 #endif
 
-#ifdef CONFIG_RTNETLINK
-
 static int inet_check_attr(struct rtmsg *r, struct rtattr **rta)
 {
 	int i;
@@ -408,8 +406,6 @@
 
 	return skb->len;
 }
-
-#endif
 
 /* Prepare and feed intra-kernel routing request.
    Really, it should be netlink message, but :-( netlink
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/fib_hash.c linux/net/ipv4/fib_hash.c
--- v2.5.2/linux/net/ipv4/fib_hash.c	Tue Aug 31 11:23:03 1999
+++ linux/net/ipv4/fib_hash.c	Tue Jan 15 10:56:35 2002
@@ -5,7 +5,7 @@
  *
  *		IPv4 FIB: lookup engine and maintenance routines.
  *
- * Version:	$Id: fib_hash.c,v 1.12 1999/08/31 07:03:27 davem Exp $
+ * Version:	$Id: fib_hash.c,v 1.13 2001/10/31 21:55:54 davem Exp $
  *
  * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
@@ -425,14 +425,9 @@
 #endif
 
 
-#ifdef CONFIG_RTNETLINK
 static void rtmsg_fib(int, struct fib_node*, int, int,
 		      struct nlmsghdr *n,
 		      struct netlink_skb_parms *);
-#else
-#define rtmsg_fib(a, b, c, d, e, f)
-#endif
-
 
 static int
 fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
@@ -796,9 +791,7 @@
 #endif
 
 
-#ifdef CONFIG_RTNETLINK
-
-extern __inline__ int
+static __inline__ int
 fn_hash_dump_bucket(struct sk_buff *skb, struct netlink_callback *cb,
 		     struct fib_table *tb,
 		     struct fn_zone *fz,
@@ -823,7 +816,7 @@
 	return skb->len;
 }
 
-extern __inline__ int
+static __inline__ int
 fn_hash_dump_zone(struct sk_buff *skb, struct netlink_callback *cb,
 		   struct fib_table *tb,
 		   struct fn_zone *fz)
@@ -894,8 +887,6 @@
 		netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT);
 }
 
-#endif /* CONFIG_RTNETLINK */
-
 #ifdef CONFIG_IP_MULTIPLE_TABLES
 struct fib_table * fib_hash_init(int id)
 #else
@@ -920,9 +911,7 @@
 	tb->tb_delete = fn_hash_delete;
 	tb->tb_flush = fn_hash_flush;
 	tb->tb_select_default = fn_hash_select_default;
-#ifdef CONFIG_RTNETLINK
 	tb->tb_dump = fn_hash_dump;
-#endif
 #ifdef CONFIG_PROC_FS
 	tb->tb_get_info = fn_hash_get_info;
 #endif
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/fib_rules.c linux/net/ipv4/fib_rules.c
--- v2.5.2/linux/net/ipv4/fib_rules.c	Tue May  1 20:59:24 2001
+++ linux/net/ipv4/fib_rules.c	Tue Jan 15 10:56:35 2002
@@ -5,7 +5,7 @@
  *
  *		IPv4 Forwarding Information Base: policy rules.
  *
- * Version:	$Id: fib_rules.c,v 1.16 2001/04/30 04:39:14 davem Exp $
+ * Version:	$Id: fib_rules.c,v 1.17 2001/10/31 21:55:54 davem Exp $
  *
  * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
@@ -395,9 +395,7 @@
 	notifier_call:	fib_rules_event,
 };
 
-#ifdef CONFIG_RTNETLINK
-
-extern __inline__ int inet_fill_rule(struct sk_buff *skb,
+static __inline__ int inet_fill_rule(struct sk_buff *skb,
 				     struct fib_rule *r,
 				     struct netlink_callback *cb)
 {
@@ -462,8 +460,6 @@
 
 	return skb->len;
 }
-
-#endif /* CONFIG_RTNETLINK */
 
 void __init fib_rules_init(void)
 {
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/fib_semantics.c linux/net/ipv4/fib_semantics.c
--- v2.5.2/linux/net/ipv4/fib_semantics.c	Tue Aug 22 08:59:00 2000
+++ linux/net/ipv4/fib_semantics.c	Tue Jan 15 10:56:35 2002
@@ -5,7 +5,7 @@
  *
  *		IPv4 Forwarding Information Base: semantics.
  *
- * Version:	$Id: fib_semantics.c,v 1.17 2000/08/19 23:22:56 davem Exp $
+ * Version:	$Id: fib_semantics.c,v 1.19 2002/01/12 07:54:56 davem Exp $
  *
  * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
@@ -134,7 +134,7 @@
 	write_unlock(&fib_info_lock);
 }
 
-extern __inline__ int nh_comp(const struct fib_info *fi, const struct fib_info *ofi)
+static __inline__ int nh_comp(const struct fib_info *fi, const struct fib_info *ofi)
 {
 	const struct fib_nh *onh = ofi->fib_nh;
 
@@ -155,7 +155,7 @@
 	return 0;
 }
 
-extern __inline__ struct fib_info * fib_find_info(const struct fib_info *nfi)
+static __inline__ struct fib_info * fib_find_info(const struct fib_info *nfi)
 {
 	for_fib_info() {
 		if (fi->fib_nhs != nfi->fib_nhs)
@@ -626,8 +626,6 @@
 	return inet_select_addr(FIB_RES_DEV(*res), FIB_RES_GW(*res), res->scope);
 }
 
-#ifdef CONFIG_RTNETLINK
-
 int
 fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
 	      u8 tb_id, u8 type, u8 scope, void *dst, int dst_len, u8 tos,
@@ -697,8 +695,6 @@
 	skb_trim(skb, b - skb->data);
 	return -1;
 }
-
-#endif /* CONFIG_RTNETLINK */
 
 #ifndef CONFIG_IP_NOSIOCRT
 
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/ip_fragment.c linux/net/ipv4/ip_fragment.c
--- v2.5.2/linux/net/ipv4/ip_fragment.c	Fri Sep  7 11:01:21 2001
+++ linux/net/ipv4/ip_fragment.c	Tue Jan 15 10:56:35 2002
@@ -5,7 +5,7 @@
  *
  *		The IP fragmentation functionality.
  *		
- * Version:	$Id: ip_fragment.c,v 1.58 2001/09/01 00:31:50 davem Exp $
+ * Version:	$Id: ip_fragment.c,v 1.59 2002/01/12 07:54:56 davem Exp $
  *
  * Authors:	Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
  *		Alan Cox <Alan.Cox@linux.org>
@@ -130,19 +130,19 @@
 atomic_t ip_frag_mem = ATOMIC_INIT(0);	/* Memory used for fragments */
 
 /* Memory Tracking Functions. */
-extern __inline__ void frag_kfree_skb(struct sk_buff *skb)
+static __inline__ void frag_kfree_skb(struct sk_buff *skb)
 {
 	atomic_sub(skb->truesize, &ip_frag_mem);
 	kfree_skb(skb);
 }
 
-extern __inline__ void frag_free_queue(struct ipq *qp)
+static __inline__ void frag_free_queue(struct ipq *qp)
 {
 	atomic_sub(sizeof(struct ipq), &ip_frag_mem);
 	kfree(qp);
 }
 
-extern __inline__ struct ipq *frag_alloc_queue(void)
+static __inline__ struct ipq *frag_alloc_queue(void)
 {
 	struct ipq *qp = kmalloc(sizeof(struct ipq), GFP_ATOMIC);
 
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/ip_input.c linux/net/ipv4/ip_input.c
--- v2.5.2/linux/net/ipv4/ip_input.c	Wed Nov  7 14:39:36 2001
+++ linux/net/ipv4/ip_input.c	Tue Jan 15 10:56:35 2002
@@ -5,7 +5,7 @@
  *
  *		The Internet Protocol (IP) module.
  *
- * Version:	$Id: ip_input.c,v 1.54 2001/11/06 22:33:52 davem Exp $
+ * Version:	$Id: ip_input.c,v 1.55 2002/01/12 07:39:45 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -224,8 +224,7 @@
 	nf_debug_ip_local_deliver(skb);
 #endif /*CONFIG_NETFILTER_DEBUG*/
 
-	/* Pull out additionl 8 bytes to save some space in protocols. */
-	if (!pskb_may_pull(skb, ihl+8))
+	if (!pskb_may_pull(skb, ihl))
 		goto out;
 	__skb_pull(skb, ihl);
 
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/ipconfig.c linux/net/ipv4/ipconfig.c
--- v2.5.2/linux/net/ipv4/ipconfig.c	Mon Jan 14 18:25:11 2002
+++ linux/net/ipv4/ipconfig.c	Tue Jan 15 10:56:35 2002
@@ -1,5 +1,5 @@
 /*
- *  $Id: ipconfig.c,v 1.42 2001/11/10 07:23:12 davem Exp $
+ *  $Id: ipconfig.c,v 1.45 2002/01/08 16:00:20 davem Exp $
  *
  *  Automatic Configuration of IP -- use DHCP, BOOTP, RARP, or
  *  user-supplied information to configure own IP address and routes.
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c
--- v2.5.2/linux/net/ipv4/ipmr.c	Thu Sep 20 14:12:56 2001
+++ linux/net/ipv4/ipmr.c	Tue Jan 15 10:56:35 2002
@@ -9,7 +9,7 @@
  *	as published by the Free Software Foundation; either version
  *	2 of the License, or (at your option) any later version.
  *
- *	Version: $Id: ipmr.c,v 1.64 2001/09/18 22:29:09 davem Exp $
+ *	Version: $Id: ipmr.c,v 1.65 2001/10/31 21:55:54 davem Exp $
  *
  *	Fixes:
  *	Michael Chastain	:	Incorrect size of copying.
@@ -294,7 +294,6 @@
 	atomic_dec(&cache_resolve_queue_len);
 
 	while((skb=skb_dequeue(&c->mfc_un.unres.unresolved))) {
-#ifdef CONFIG_RTNETLINK
 		if (skb->nh.iph->version == 0) {
 			struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr));
 			nlh->nlmsg_type = NLMSG_ERROR;
@@ -303,7 +302,6 @@
 			((struct nlmsgerr*)NLMSG_DATA(nlh))->error = -ETIMEDOUT;
 			netlink_unicast(rtnl, skb, NETLINK_CB(skb).dst_pid, MSG_DONTWAIT);
 		} else
-#endif
 			kfree_skb(skb);
 	}
 
@@ -501,7 +499,6 @@
 	 */
 
 	while((skb=__skb_dequeue(&uc->mfc_un.unres.unresolved))) {
-#ifdef CONFIG_RTNETLINK
 		if (skb->nh.iph->version == 0) {
 			int err;
 			struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr));
@@ -516,7 +513,6 @@
 			}
 			err = netlink_unicast(rtnl, skb, NETLINK_CB(skb).dst_pid, MSG_DONTWAIT);
 		} else
-#endif
 			ip_mr_forward(skb, c, 0);
 	}
 }
@@ -1522,8 +1518,6 @@
 }
 #endif
 
-#ifdef CONFIG_RTNETLINK
-
 static int
 ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm)
 {
@@ -1598,7 +1592,6 @@
 	read_unlock(&mrt_lock);
 	return err;
 }
-#endif
 
 #ifdef CONFIG_PROC_FS	
 /*
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/netfilter/Config.in linux/net/ipv4/netfilter/Config.in
--- v2.5.2/linux/net/ipv4/netfilter/Config.in	Tue Oct 30 15:08:12 2001
+++ linux/net/ipv4/netfilter/Config.in	Tue Jan 15 10:56:35 2002
@@ -10,7 +10,7 @@
   dep_tristate '  IRC protocol support' CONFIG_IP_NF_IRC $CONFIG_IP_NF_CONNTRACK
 fi
 
-if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_NETLINK" = "y" ]; then
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   tristate 'Userspace queueing via NETLINK (EXPERIMENTAL)' CONFIG_IP_NF_QUEUE
 fi
 tristate 'IP tables support (required for filtering/masq/NAT)' CONFIG_IP_NF_IPTABLES
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/netfilter/ip_fw_compat_redir.c linux/net/ipv4/netfilter/ip_fw_compat_redir.c
--- v2.5.2/linux/net/ipv4/netfilter/ip_fw_compat_redir.c	Mon Jan 14 18:25:11 2002
+++ linux/net/ipv4/netfilter/ip_fw_compat_redir.c	Wed Jan 16 10:29:38 2002
@@ -20,6 +20,9 @@
 
 #include <linux/netfilter_ipv4/lockhelp.h>
 
+/* Very simple timeout pushed back by each packet */
+#define REDIR_TIMEOUT (240*HZ)
+
 static DECLARE_LOCK(redir_lock);
 #define ASSERT_READ_LOCK(x) MUST_BE_LOCKED(&redir_lock)
 #define ASSERT_WRITE_LOCK(x) MUST_BE_LOCKED(&redir_lock)
@@ -150,6 +153,14 @@
 	skb->nfcache |= NFC_ALTERED;
 }
 
+static void destroyme(unsigned long me)
+{
+	LOCK_BH(&redir_lock);
+	LIST_DELETE(&redirs, (struct redir *)me);
+	UNLOCK_BH(&redir_lock);
+	kfree((struct redir *)me);
+}
+
 /* REDIRECT a packet. */
 unsigned int
 do_redirect(struct sk_buff *skb,
@@ -172,6 +183,10 @@
 		struct udphdr *udph = (struct udphdr *)((u_int32_t *)iph
 							+ iph->ihl);
 
+		/* Must have whole header */
+		if (skb->len < iph->ihl*4 + sizeof(*udph))
+			return NF_DROP;
+
 		if (udph->check) /* 0 is a special case meaning no checksum */
 			udph->check = cheat_check(~iph->daddr, newdst,
 					  cheat_check(udph->dest ^ 0xFFFF,
@@ -191,6 +206,10 @@
 		struct redir *redir;
 		int ret;
 
+		/* Must have whole header */
+		if (skb->len < iph->ihl*4 + sizeof(*tcph))
+			return NF_DROP;
+
 		DEBUGP("Doing tcp redirect. %08X:%u %08X:%u -> %08X:%u\n",
 		       iph->saddr, tcph->source, iph->daddr, tcph->dest,
 		       newdst, redirpt);
@@ -206,7 +225,9 @@
 			}
 			list_prepend(&redirs, redir);
 			init_timer(&redir->destroyme);
-			redir->destroyme.expires = jiffies + 75*HZ;
+			redir->destroyme.function = destroyme;
+			redir->destroyme.data = (unsigned long)redir;
+			redir->destroyme.expires = jiffies + REDIR_TIMEOUT;
 			add_timer(&redir->destroyme);
 		}
 		/* In case mangling has changed, rewrite this part. */
@@ -227,13 +248,6 @@
 	}
 }
 
-static void destroyme(unsigned long me)
-{
-	LOCK_BH(&redir_lock);
-	LIST_DELETE(&redirs, (struct redir *)me);
-	UNLOCK_BH(&redir_lock);
-}
-
 /* Incoming packet: is it a reply to a masqueraded connection, or
    part of an already-redirected TCP connection? */
 void
@@ -247,15 +261,18 @@
 	if (iph->protocol != IPPROTO_TCP)
 		return;
 
+	/* Must have whole header */
+	if (skb->len < iph->ihl*4 + sizeof(*tcph))
+		return;
+
 	LOCK_BH(&redir_lock);
 	redir = find_redir(iph->saddr, iph->daddr, tcph->source, tcph->dest);
 	if (redir) {
 		DEBUGP("Doing tcp redirect again.\n");
 		do_tcp_redir(skb, redir);
-		if (tcph->rst || tcph->fin) {
-			redir->destroyme.function = destroyme;
-			redir->destroyme.data = (unsigned long)redir;
-			mod_timer(&redir->destroyme, 75*HZ);
+		if (del_timer(&redir->destroyme)) {
+			redir->destroyme.expires = jiffies + REDIR_TIMEOUT;
+			add_timer(&redir->destroyme);
 		}
 	}
 	UNLOCK_BH(&redir_lock);
@@ -272,15 +289,18 @@
 	if (iph->protocol != IPPROTO_TCP)
 		return;
 
+	/* Must have whole header */
+	if (skb->len < iph->ihl*4 + sizeof(*tcph))
+		return;
+
 	LOCK_BH(&redir_lock);
 	redir = find_unredir(iph->saddr, iph->daddr, tcph->source, tcph->dest);
 	if (redir) {
 		DEBUGP("Doing tcp unredirect.\n");
 		do_tcp_unredir(skb, redir);
-		if (tcph->rst || tcph->fin) {
-			redir->destroyme.function = destroyme;
-			redir->destroyme.data = (unsigned long)redir;
-			mod_timer(&redir->destroyme, 75*HZ);
+		if (del_timer(&redir->destroyme)) {
+			redir->destroyme.expires = jiffies + REDIR_TIMEOUT;
+			add_timer(&redir->destroyme);
 		}
 	}
 	UNLOCK_BH(&redir_lock);
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/netfilter/ip_nat_standalone.c linux/net/ipv4/netfilter/ip_nat_standalone.c
--- v2.5.2/linux/net/ipv4/netfilter/ip_nat_standalone.c	Sun Sep 30 12:26:08 2001
+++ linux/net/ipv4/netfilter/ip_nat_standalone.c	Tue Jan 15 10:56:35 2002
@@ -166,19 +166,16 @@
 	return ip_nat_fn(hooknum, pskb, in, out, okfn);
 }
 
-/* FIXME: change in oif may mean change in hh_len.  Check and realloc
-   --RR */
-static int
-route_me_harder(struct sk_buff *skb)
+static int route_me_harder(struct sk_buff **pskb)
 {
-	struct iphdr *iph = skb->nh.iph;
+	struct iphdr *iph = (*pskb)->nh.iph;
 	struct rtable *rt;
 	struct rt_key key = { dst:iph->daddr,
 			      src:iph->saddr,
-			      oif:skb->sk ? skb->sk->bound_dev_if : 0,
+			      oif:(*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0,
 			      tos:RT_TOS(iph->tos)|RTO_CONN,
 #ifdef CONFIG_IP_ROUTE_FWMARK
-			      fwmark:skb->nfmark
+			      fwmark:(*pskb)->nfmark
 #endif
 			    };
 
@@ -188,9 +185,24 @@
 	}
 
 	/* Drop old route. */
-	dst_release(skb->dst);
+	dst_release((*pskb)->dst);
 
-	skb->dst = &rt->u.dst;
+	(*pskb)->dst = &rt->u.dst;
+
+	/* Change in oif may mean change in hh_len. */
+	if (skb_headroom(*pskb) < (*pskb)->dst->dev->hard_header_len) {
+		struct sk_buff *nskb;
+
+		nskb = skb_realloc_headroom(*pskb,
+					    (*pskb)->dst->dev
+					    ->hard_header_len);
+		if (!nskb)
+			return -ENOMEM;
+		if ((*pskb)->sk)
+			skb_set_owner_w(nskb, (*pskb)->sk);
+		kfree_skb(*pskb);
+		*pskb = nskb;
+	}
 	return 0;
 }
 
@@ -216,7 +228,7 @@
 	if (ret != NF_DROP && ret != NF_STOLEN
 	    && ((*pskb)->nh.iph->saddr != saddr
 		|| (*pskb)->nh.iph->daddr != daddr))
-		return route_me_harder(*pskb) == 0 ? ret : NF_DROP;
+		return route_me_harder(pskb) == 0 ? ret : NF_DROP;
 	return ret;
 }
 
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/route.c linux/net/ipv4/route.c
--- v2.5.2/linux/net/ipv4/route.c	Tue Oct 30 15:08:12 2001
+++ linux/net/ipv4/route.c	Tue Jan 15 10:56:35 2002
@@ -5,7 +5,7 @@
  *
  *		ROUTE - implementation of the IP router.
  *
- * Version:	$Id: route.c,v 1.101 2001/10/20 00:00:11 davem Exp $
+ * Version:	$Id: route.c,v 1.103 2002/01/12 07:44:09 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -214,7 +214,7 @@
 {
 	int len = 0;
 	off_t pos = 128;
-	char temp[129];
+	char temp[256];
 	struct rtable *r;
 	int i;
 
@@ -2013,7 +2013,6 @@
 	return ip_route_output_slow(rp, key);
 }	
 
-#ifdef CONFIG_RTNETLINK
 static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
 			int nowait)
 {
@@ -2218,8 +2217,6 @@
 	cb->args[1] = idx;
 	return skb->len;
 }
-
-#endif /* CONFIG_RTNETLINK */
 
 void ip_rt_multicast_event(struct in_device *in_dev)
 {
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.5.2/linux/net/ipv4/tcp.c	Tue Oct 30 15:08:12 2001
+++ linux/net/ipv4/tcp.c	Tue Jan 15 10:56:35 2002
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp.c,v 1.214 2001/10/20 00:00:11 davem Exp $
+ * Version:	$Id: tcp.c,v 1.215 2001/10/31 08:17:58 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -2442,6 +2442,7 @@
 
 
 extern void __skb_cb_too_small_for_tcp(int, int);
+extern void tcpdiag_init(void);
 
 void __init tcp_init(void)
 {
@@ -2553,4 +2554,6 @@
 
 	printk("TCP: Hash tables configured (established %d bind %d)\n",
 	       tcp_ehash_size<<1, tcp_bhash_size);
+
+	tcpdiag_init();
 }
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/tcp_diag.c linux/net/ipv4/tcp_diag.c
--- v2.5.2/linux/net/ipv4/tcp_diag.c	Wed Dec 31 16:00:00 1969
+++ linux/net/ipv4/tcp_diag.c	Tue Jan 15 10:56:35 2002
@@ -0,0 +1,609 @@
+/*
+ * tcp_diag.c	Module for monitoring TCP sockets.
+ *
+ * Version:	$Id: tcp_diag.c,v 1.2 2001/11/05 09:42:22 davem Exp $
+ *
+ * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ *	This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/random.h>
+#include <linux/cache.h>
+#include <linux/init.h>
+
+#include <net/icmp.h>
+#include <net/tcp.h>
+#include <net/ipv6.h>
+#include <net/inet_common.h>
+
+#include <linux/inet.h>
+#include <linux/stddef.h>
+
+#include <linux/tcp_diag.h>
+
+static struct sock *tcpnl;
+
+
+#define TCPDIAG_PUT(skb, attrtype, attrlen) \
+({ int rtalen = RTA_LENGTH(attrlen);        \
+   struct rtattr *rta;                      \
+   if (skb_tailroom(skb) < RTA_ALIGN(rtalen)) goto nlmsg_failure; \
+   rta = (void*)__skb_put(skb, RTA_ALIGN(rtalen)); \
+   rta->rta_type = attrtype;                \
+   rta->rta_len = rtalen;                   \
+   RTA_DATA(rta); })
+
+static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk,
+			int ext, u32 pid, u32 seq)
+{
+	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+	struct tcpdiagmsg *r;
+	struct nlmsghdr  *nlh;
+	struct tcp_info  *info = NULL;
+	struct tcpdiag_meminfo  *minfo = NULL;
+	unsigned char	 *b = skb->tail;
+
+	nlh = NLMSG_PUT(skb, pid, seq, TCPDIAG_GETSOCK, sizeof(*r));
+	r = NLMSG_DATA(nlh);
+	if (sk->state != TCP_TIME_WAIT) {
+		if (ext & (1<<(TCPDIAG_MEMINFO-1)))
+			minfo = TCPDIAG_PUT(skb, TCPDIAG_MEMINFO, sizeof(*minfo));
+		if (ext & (1<<(TCPDIAG_INFO-1)))
+			info = TCPDIAG_PUT(skb, TCPDIAG_INFO, sizeof(*info));
+	}
+	r->tcpdiag_family = sk->family;
+	r->tcpdiag_state = sk->state;
+	r->tcpdiag_timer = 0;
+	r->tcpdiag_retrans = 0;
+
+	r->id.tcpdiag_sport = sk->sport;
+	r->id.tcpdiag_dport = sk->dport;
+	r->id.tcpdiag_src[0] = sk->rcv_saddr;
+	r->id.tcpdiag_dst[0] = sk->daddr;
+	r->id.tcpdiag_if = sk->bound_dev_if;
+	*((struct sock **)&r->id.tcpdiag_cookie) = sk;
+
+	if (r->tcpdiag_state == TCP_TIME_WAIT) {
+		struct tcp_tw_bucket *tw = (struct tcp_tw_bucket*)sk;
+		long tmo = tw->ttd - jiffies;
+		if (tmo < 0)
+			tmo = 0;
+
+		r->tcpdiag_state = tw->substate;
+		r->tcpdiag_timer = 3;
+		r->tcpdiag_expires = (tmo*1000+HZ-1)/HZ;
+		r->tcpdiag_rqueue = 0;
+		r->tcpdiag_wqueue = 0;
+		r->tcpdiag_uid = 0;
+		r->tcpdiag_inode = 0;
+#ifdef CONFIG_IPV6
+		if (r->tcpdiag_family == AF_INET6) {
+			memcpy(r->id.tcpdiag_src, &tw->v6_rcv_saddr, 16);
+			memcpy(r->id.tcpdiag_dst, &tw->v6_daddr, 16);
+		}
+#endif
+		nlh->nlmsg_len = skb->tail - b;
+		return skb->len;
+	}
+
+#ifdef CONFIG_IPV6
+	if (r->tcpdiag_family == AF_INET6) {
+		memcpy(r->id.tcpdiag_src, &sk->net_pinfo.af_inet6.rcv_saddr, 16);
+		memcpy(r->id.tcpdiag_dst, &sk->net_pinfo.af_inet6.daddr, 16);
+	}
+#endif
+
+#define EXPIRES_IN_MS(tmo)  ((tmo-jiffies)*1000+HZ-1)/HZ
+
+	if (tp->pending == TCP_TIME_RETRANS) {
+		r->tcpdiag_timer = 1;
+		r->tcpdiag_retrans = tp->retransmits;
+		r->tcpdiag_expires = EXPIRES_IN_MS(tp->timeout);
+	} else if (tp->pending == TCP_TIME_PROBE0) {
+		r->tcpdiag_timer = 4;
+		r->tcpdiag_retrans = tp->probes_out;
+		r->tcpdiag_expires = EXPIRES_IN_MS(tp->timeout);
+	} else if (timer_pending(&sk->timer)) {
+		r->tcpdiag_timer = 2;
+		r->tcpdiag_retrans = tp->probes_out;
+		r->tcpdiag_expires = EXPIRES_IN_MS(sk->timer.expires);
+	} else {
+		r->tcpdiag_timer = 0;
+		r->tcpdiag_expires = 0;
+	}
+#undef EXPIRES_IN_MS
+
+	r->tcpdiag_rqueue = tp->rcv_nxt - tp->copied_seq;
+	r->tcpdiag_wqueue = tp->write_seq - tp->snd_una;
+	r->tcpdiag_uid = sock_i_uid(sk);
+	r->tcpdiag_inode = sock_i_ino(sk);
+
+	if (minfo) {
+		minfo->tcpdiag_rmem = atomic_read(&sk->rmem_alloc);
+		minfo->tcpdiag_wmem = sk->wmem_queued;
+		minfo->tcpdiag_fmem = sk->forward_alloc;
+		minfo->tcpdiag_tmem = atomic_read(&sk->wmem_alloc);
+	}
+
+	if (info) {
+		u32 now = tcp_time_stamp;
+
+		info->tcpi_state = sk->state;
+		info->tcpi_ca_state = tp->ca_state;
+		info->tcpi_retransmits = tp->retransmits;
+		info->tcpi_probes = tp->probes_out;
+		info->tcpi_backoff = tp->backoff;
+		info->tcpi_options = 0;
+		if (tp->tstamp_ok)
+			info->tcpi_options |= TCPI_OPT_TIMESTAMPS;
+		if (tp->sack_ok)
+			info->tcpi_options |= TCPI_OPT_SACK;
+		if (tp->wscale_ok) {
+			info->tcpi_options |= TCPI_OPT_WSCALE;
+			info->tcpi_snd_wscale = tp->snd_wscale;
+			info->tcpi_rcv_wscale = tp->rcv_wscale;
+		} else {
+			info->tcpi_snd_wscale = 0;
+			info->tcpi_rcv_wscale = 0;
+		}
+#ifdef CONFIG_INET_ECN
+		if (tp->ecn_flags&TCP_ECN_OK)
+			info->tcpi_options |= TCPI_OPT_ECN;
+#endif
+
+		info->tcpi_rto = (1000000*tp->rto)/HZ;
+		info->tcpi_ato = (1000000*tp->ack.ato)/HZ;
+		info->tcpi_snd_mss = tp->mss_cache;
+		info->tcpi_rcv_mss = tp->ack.rcv_mss;
+
+		info->tcpi_unacked = tp->packets_out;
+		info->tcpi_sacked = tp->sacked_out;
+		info->tcpi_lost = tp->lost_out;
+		info->tcpi_retrans = tp->retrans_out;
+		info->tcpi_fackets = tp->fackets_out;
+
+		info->tcpi_last_data_sent = ((now - tp->lsndtime)*1000)/HZ;
+		info->tcpi_last_ack_sent = 0;
+		info->tcpi_last_data_recv = ((now - tp->ack.lrcvtime)*1000)/HZ;
+		info->tcpi_last_ack_recv = ((now - tp->rcv_tstamp)*1000)/HZ;
+
+		info->tcpi_pmtu = tp->pmtu_cookie;
+		info->tcpi_rcv_ssthresh = tp->rcv_ssthresh;
+		info->tcpi_rtt = ((1000000*tp->srtt)/HZ)>>3;
+		info->tcpi_rttvar = ((1000000*tp->mdev)/HZ)>>2;
+		info->tcpi_snd_ssthresh = tp->snd_ssthresh;
+		info->tcpi_snd_cwnd = tp->snd_cwnd;
+		info->tcpi_advmss = tp->advmss;
+		info->tcpi_reordering = tp->reordering;
+	}
+
+	nlh->nlmsg_len = skb->tail - b;
+	return skb->len;
+
+nlmsg_failure:
+	skb_trim(skb, b - skb->data);
+	return -1;
+}
+
+extern struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, int dif);
+#ifdef CONFIG_IPV6
+extern struct sock *tcp_v6_lookup(struct in6_addr *saddr, u16 sport,
+				  struct in6_addr *daddr, u16 dport,
+				  int dif);
+#endif
+
+static int tcpdiag_get_exact(struct sk_buff *in_skb, struct nlmsghdr *nlh)
+{
+	int err;
+	struct sock *sk;
+	struct tcpdiagreq *req = NLMSG_DATA(nlh);
+	struct sk_buff *rep;
+
+	if (req->tcpdiag_family == AF_INET) {
+		sk = tcp_v4_lookup(req->id.tcpdiag_dst[0], req->id.tcpdiag_dport,
+				   req->id.tcpdiag_src[0], req->id.tcpdiag_sport,
+				   req->id.tcpdiag_if);
+	}
+#ifdef CONFIG_IPV6
+	else if (req->tcpdiag_family == AF_INET6) {
+		sk = tcp_v6_lookup((struct in6_addr*)req->id.tcpdiag_dst, req->id.tcpdiag_dport,
+				   (struct in6_addr*)req->id.tcpdiag_src, req->id.tcpdiag_sport,
+				   req->id.tcpdiag_if);
+	}
+#endif
+	else {
+		return -EINVAL;
+	}
+
+	if (sk == NULL)
+		return -ENOENT;
+
+	err = -ESTALE;
+	if ((req->id.tcpdiag_cookie[0] != TCPDIAG_NOCOOKIE ||
+	     req->id.tcpdiag_cookie[1] != TCPDIAG_NOCOOKIE) &&
+	    sk != *((struct sock **)&req->id.tcpdiag_cookie[0]))
+		goto out;
+
+	err = -ENOMEM;
+	rep = alloc_skb(NLMSG_SPACE(sizeof(struct tcpdiagmsg)+
+				    sizeof(struct tcpdiag_meminfo)+
+				    sizeof(struct tcp_info)+64), GFP_KERNEL);
+	if (!rep)
+		goto out;
+
+	if (tcpdiag_fill(rep, sk, req->tcpdiag_ext,
+			 NETLINK_CB(in_skb).pid,
+			 nlh->nlmsg_seq) <= 0)
+		BUG();
+
+	err = netlink_unicast(tcpnl, rep, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
+	if (err > 0)
+		err = 0;
+
+out:
+	if (sk) {
+		if (sk->state == TCP_TIME_WAIT)
+			tcp_tw_put((struct tcp_tw_bucket*)sk);
+		else
+			sock_put(sk);
+	}
+	return err;
+}
+
+int bitstring_match(u32 *a1, u32 *a2, int bits)
+{
+	int words = bits >> 5;
+
+	bits &= 0x1f;
+
+	if (words) {
+		if (memcmp(a1, a2, words << 2))
+			return 0;
+	}
+	if (bits) {
+		__u32 w1, w2;
+		__u32 mask;
+
+		w1 = a1[words];
+		w2 = a2[words];
+
+		mask = htonl((0xffffffff) << (32 - bits));
+
+		if ((w1 ^ w2) & mask)
+			return 0;
+	}
+
+	return 1;
+}
+
+
+int tcpdiag_bc_run(char *bc, int len, struct sock *sk)
+{
+	while (len > 0) {
+		int yes = 1;
+		struct tcpdiag_bc_op *op = (struct tcpdiag_bc_op*)bc;
+
+		switch (op->code) {
+		case TCPDIAG_BC_NOP:
+			break;
+		case TCPDIAG_BC_JMP:
+			yes = 0;
+			break;
+		case TCPDIAG_BC_S_GE:
+			yes = (sk->num >= op[1].no);
+			break;
+		case TCPDIAG_BC_S_LE:
+			yes = (sk->num <= op[1].no);
+			break;
+		case TCPDIAG_BC_D_GE:
+			yes = (ntohs(sk->dport) >= op[1].no);
+			break;
+		case TCPDIAG_BC_D_LE:
+			yes = (ntohs(sk->dport) <= op[1].no);
+			break;
+		case TCPDIAG_BC_AUTO:
+			yes = !(sk->userlocks&SOCK_BINDPORT_LOCK);
+			break;
+		case TCPDIAG_BC_S_COND:
+		case TCPDIAG_BC_D_COND:
+		{
+			struct tcpdiag_hostcond *cond = (struct tcpdiag_hostcond*)(op+1);
+			u32 *addr;
+
+			if (cond->port != -1 &&
+			    cond->port != (op->code == TCPDIAG_BC_S_COND ? sk->num : ntohs(sk->dport))) {
+				yes = 0;
+				break;
+			}
+			
+			if (cond->prefix_len == 0)
+				break;
+
+#ifdef CONFIG_IPV6
+			if (sk->family == AF_INET6) {
+				if (op->code == TCPDIAG_BC_S_COND)
+					addr = (u32*)&sk->net_pinfo.af_inet6.rcv_saddr;
+				else
+					addr = (u32*)&sk->net_pinfo.af_inet6.daddr;
+			} else
+#endif
+			{
+				if (op->code == TCPDIAG_BC_S_COND)
+					addr = &sk->rcv_saddr;
+				else
+					addr = &sk->daddr;
+			}
+
+			if (bitstring_match(addr, cond->addr, cond->prefix_len))
+				break;
+			if (sk->family == AF_INET6 && cond->family == AF_INET) {
+				if (addr[0] == 0 && addr[1] == 0 &&
+				    addr[2] == __constant_htonl(0xffff) &&
+				    bitstring_match(addr+3, cond->addr, cond->prefix_len))
+					break;
+			}
+			yes = 0;
+			break;
+		}
+		}
+
+		if (yes) { 
+			len -= op->yes;
+			bc += op->yes;
+		} else {
+			len -= op->no;
+			bc += op->no;
+		}
+	}
+	return (len == 0);
+}
+
+int valid_cc(char *bc, int len, int cc)
+{
+	while (len >= 0) {
+		struct tcpdiag_bc_op *op = (struct tcpdiag_bc_op*)bc;
+
+		if (cc > len)
+			return 0;
+		if (cc == len)
+			return 1;
+		if (op->yes < 4)
+			return 0;
+		len -= op->yes;
+		bc  += op->yes;
+	}
+	return 0;
+}
+
+int tcpdiag_bc_audit(char *bytecode, int bytecode_len)
+{
+	char *bc = bytecode;
+	int  len = bytecode_len;
+
+	while (len > 0) {
+		struct tcpdiag_bc_op *op = (struct tcpdiag_bc_op*)bc;
+
+//printk("BC: %d %d %d {%d} / %d\n", op->code, op->yes, op->no, op[1].no, len);
+		switch (op->code) {
+		case TCPDIAG_BC_AUTO:
+		case TCPDIAG_BC_S_COND:
+		case TCPDIAG_BC_D_COND:
+		case TCPDIAG_BC_S_GE:
+		case TCPDIAG_BC_S_LE:
+		case TCPDIAG_BC_D_GE:
+		case TCPDIAG_BC_D_LE:
+			if (op->yes < 4 || op->yes > len+4)
+				return -EINVAL;
+		case TCPDIAG_BC_JMP:
+			if (op->no < 4 || op->no > len+4)
+				return -EINVAL;
+			if (op->no < len &&
+			    !valid_cc(bytecode, bytecode_len, len-op->no))
+				return -EINVAL;
+			break;
+		case TCPDIAG_BC_NOP:
+			if (op->yes < 4 || op->yes > len+4)
+				return -EINVAL;
+			break;
+		default:
+			return -EINVAL;
+		}
+		bc += op->yes;
+		len -= op->yes;
+	}
+	return len == 0 ? 0 : -EINVAL;
+}
+
+
+int tcpdiag_dump(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	int i, num;
+	int s_i, s_num;
+	struct tcpdiagreq *r = NLMSG_DATA(cb->nlh);
+	struct rtattr *bc = NULL;
+
+	if (cb->nlh->nlmsg_len > 4+NLMSG_SPACE(sizeof(struct tcpdiagreq)))
+		bc = (struct rtattr*)(r+1);
+
+	s_i = cb->args[1];
+	s_num = num = cb->args[2];
+
+	if (cb->args[0] == 0) {
+		if (!(r->tcpdiag_states&(TCPF_LISTEN|TCPF_SYN_RECV)))
+			goto skip_listen_ht;
+		tcp_listen_lock();
+		for (i = s_i; i < TCP_LHTABLE_SIZE; i++) {
+			struct sock *sk = tcp_listening_hash[i];
+
+			if (i > s_i)
+				s_num = 0;
+
+			for (sk = tcp_listening_hash[i], num = 0;
+			     sk != NULL;
+			     sk = sk->next, num++) {
+				if (num < s_num)
+					continue;
+				if (!(r->tcpdiag_states&TCPF_LISTEN) ||
+				    r->id.tcpdiag_dport)
+					continue;
+				if (r->id.tcpdiag_sport != sk->sport && r->id.tcpdiag_sport)
+					continue;
+				if (bc && !tcpdiag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), sk))
+					continue;
+				if (tcpdiag_fill(skb, sk, r->tcpdiag_ext,
+						 NETLINK_CB(cb->skb).pid,
+						 cb->nlh->nlmsg_seq) <= 0) {
+					tcp_listen_unlock();
+					goto done;
+				}
+			}
+		}
+		tcp_listen_unlock();
+skip_listen_ht:
+		cb->args[0] = 1;
+		s_i = num = s_num = 0;
+	}
+
+	if (!(r->tcpdiag_states&~(TCPF_LISTEN|TCPF_SYN_RECV)))
+		return skb->len;
+
+	for (i = s_i; i < tcp_ehash_size; i++) {
+		struct tcp_ehash_bucket *head = &tcp_ehash[i];
+		struct sock *sk;
+
+		if (i > s_i)
+			s_num = 0;
+
+		read_lock_bh(&head->lock);
+
+		for (sk = head->chain, num = 0;
+		     sk != NULL;
+		     sk = sk->next, num++) {
+			if (num < s_num)
+				continue;
+			if (!(r->tcpdiag_states&(1<<sk->state)))
+				continue;
+			if (r->id.tcpdiag_sport != sk->sport && r->id.tcpdiag_sport)
+				continue;
+			if (r->id.tcpdiag_dport != sk->dport && r->id.tcpdiag_dport)
+				continue;
+			if (bc && !tcpdiag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), sk))
+				continue;
+			if (tcpdiag_fill(skb, sk, r->tcpdiag_ext,
+					 NETLINK_CB(cb->skb).pid,
+					 cb->nlh->nlmsg_seq) <= 0) {
+				read_unlock_bh(&head->lock);
+				goto done;
+			}
+		}
+
+		if (r->tcpdiag_states&TCPF_TIME_WAIT) {
+			for (sk = tcp_ehash[i+tcp_ehash_size].chain;
+			     sk != NULL;
+			     sk = sk->next, num++) {
+				if (num < s_num)
+					continue;
+				if (!(r->tcpdiag_states&(1<<sk->zapped)))
+					continue;
+				if (r->id.tcpdiag_sport != sk->sport && r->id.tcpdiag_sport)
+					continue;
+				if (r->id.tcpdiag_dport != sk->dport && r->id.tcpdiag_dport)
+					continue;
+				if (bc && !tcpdiag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), sk))
+					continue;
+				if (tcpdiag_fill(skb, sk, r->tcpdiag_ext,
+						 NETLINK_CB(cb->skb).pid,
+						 cb->nlh->nlmsg_seq) <= 0) {
+					read_unlock_bh(&head->lock);
+					goto done;
+				}
+			}
+		}
+		read_unlock_bh(&head->lock);
+	}
+
+done:
+	cb->args[1] = i;
+	cb->args[2] = num;
+	return skb->len;
+}
+
+static int tcpdiag_dump_done(struct netlink_callback *cb)
+{
+	return 0;
+}
+
+
+static __inline__ int
+tcpdiag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+{
+	if (!(nlh->nlmsg_flags&NLM_F_REQUEST))
+		return 0;
+
+	if (nlh->nlmsg_type != TCPDIAG_GETSOCK)
+		goto err_inval;
+
+	if (NLMSG_LENGTH(sizeof(struct tcpdiagreq)) > skb->len)
+		goto err_inval;
+
+	if (nlh->nlmsg_flags&NLM_F_DUMP) {
+		if (nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(struct tcpdiagreq))) {
+			struct rtattr *rta = (struct rtattr*)(NLMSG_DATA(nlh) + sizeof(struct tcpdiagreq));
+			if (rta->rta_type != TCPDIAG_REQ_BYTECODE ||
+			    rta->rta_len < 8 ||
+			    rta->rta_len > nlh->nlmsg_len - NLMSG_SPACE(sizeof(struct tcpdiagreq)))
+				goto err_inval;
+			if (tcpdiag_bc_audit(RTA_DATA(rta), RTA_PAYLOAD(rta)))
+				goto err_inval;
+		}
+		return netlink_dump_start(tcpnl, skb, nlh,
+					  tcpdiag_dump,
+					  tcpdiag_dump_done);
+	} else {
+		return tcpdiag_get_exact(skb, nlh);
+	}
+
+err_inval:
+	return -EINVAL;
+}
+
+
+extern __inline__ void tcpdiag_rcv_skb(struct sk_buff *skb)
+{
+	int err;
+	struct nlmsghdr * nlh;
+
+	if (skb->len >= NLMSG_SPACE(0)) {
+		nlh = (struct nlmsghdr *)skb->data;
+		if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
+			return;
+		err = tcpdiag_rcv_msg(skb, nlh);
+		if (err) 
+			netlink_ack(skb, nlh, err);
+	}
+}
+
+static void tcpdiag_rcv(struct sock *sk, int len)
+{
+	struct sk_buff *skb;
+
+	while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
+		tcpdiag_rcv_skb(skb);
+		kfree_skb(skb);
+	}
+}
+
+void __init tcpdiag_init(void)
+{
+	tcpnl = netlink_kernel_create(NETLINK_TCPDIAG, tcpdiag_rcv);
+	if (tcpnl == NULL)
+		panic("tcpdiag_init: Cannot create netlink socket.");
+}
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.5.2/linux/net/ipv4/tcp_input.c	Tue Dec 18 14:56:41 2001
+++ linux/net/ipv4/tcp_input.c	Tue Jan 15 10:56:35 2002
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_input.c,v 1.238 2001/10/20 00:00:11 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.242 2001/12/11 06:11:53 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.5.2/linux/net/ipv4/tcp_ipv4.c	Mon Nov  5 09:46:12 2001
+++ linux/net/ipv4/tcp_ipv4.c	Tue Jan 15 10:56:35 2002
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_ipv4.c,v 1.235 2001/10/26 14:51:13 davem Exp $
+ * Version:	$Id: tcp_ipv4.c,v 1.238 2002/01/15 08:49:21 davem Exp $
  *
  *		IPv4 specific functions
  *
@@ -754,21 +754,19 @@
 }
 
 static struct open_request *tcp_v4_search_req(struct tcp_opt *tp, 
-					      struct iphdr *iph,
-					      struct tcphdr *th,
-					      struct open_request ***prevp)
+					      struct open_request ***prevp,
+					      __u16 rport,
+					      __u32 raddr, __u32 laddr)
 {
 	struct tcp_listen_opt *lopt = tp->listen_opt;
 	struct open_request *req, **prev;  
-	__u16 rport = th->source;
-	__u32 raddr = iph->saddr;
 
 	for (prev = &lopt->syn_table[tcp_v4_synq_hash(raddr, rport)];
 	     (req = *prev) != NULL;
 	     prev = &req->dl_next) {
 		if (req->rmt_port == rport &&
 		    req->af.v4_req.rmt_addr == raddr &&
-		    req->af.v4_req.loc_addr == iph->daddr &&
+		    req->af.v4_req.loc_addr == laddr &&
 		    TCP_INET_FAMILY(req->class->family)) {
 			BUG_TRAP(req->sk == NULL);
 			*prevp = prev;
@@ -939,7 +937,9 @@
 		if (sk->lock.users != 0)
 			goto out;
 
-		req = tcp_v4_search_req(tp, iph, th, &prev); 
+		req = tcp_v4_search_req(tp, &prev,
+					th->dest,
+					iph->daddr, iph->saddr); 
 		if (!req)
 			goto out;
 
@@ -1473,11 +1473,14 @@
 {
 	struct open_request *req, **prev;
 	struct tcphdr *th = skb->h.th;
+	struct iphdr *iph = skb->nh.iph;
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 	struct sock *nsk;
 
 	/* Find possible connection requests. */
-	req = tcp_v4_search_req(tp, skb->nh.iph, th, &prev);
+	req = tcp_v4_search_req(tp, &prev,
+				th->source,
+				iph->saddr, iph->daddr);
 	if (req)
 		return tcp_check_req(sk, skb, req, prev);
 
@@ -2061,7 +2064,7 @@
 	/* First, walk listening socket table. */
 	tcp_listen_lock();
 	for(i = 0; i < TCP_LHTABLE_SIZE; i++) {
-		struct sock *sk = tcp_listening_hash[i];
+		struct sock *sk;
 		struct tcp_listen_opt *lopt;
 		int k;
 
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- v2.5.2/linux/net/ipv4/tcp_output.c	Mon Jan 14 18:25:11 2002
+++ linux/net/ipv4/tcp_output.c	Tue Jan 15 10:56:35 2002
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_output.c,v 1.143 2001/10/26 14:51:13 davem Exp $
+ * Version:	$Id: tcp_output.c,v 1.145 2002/01/11 08:45:37 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
diff -u --recursive --new-file v2.5.2/linux/net/ipv4/udp.c linux/net/ipv4/udp.c
--- v2.5.2/linux/net/ipv4/udp.c	Wed Oct 17 14:16:39 2001
+++ linux/net/ipv4/udp.c	Tue Jan 15 10:56:35 2002
@@ -5,7 +5,7 @@
  *
  *		The User Datagram Protocol (UDP).
  *
- * Version:	$Id: udp.c,v 1.100 2001/10/15 12:34:50 davem Exp $
+ * Version:	$Id: udp.c,v 1.101 2002/01/12 07:39:45 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -886,6 +886,9 @@
 	/*
 	 *	Validate the packet and the UDP length.
 	 */
+	if (!pskb_may_pull(skb, sizeof(struct udphdr)))
+		goto no_header;
+
 	ulen = ntohs(skb->h.uh->len);
 
 	if (ulen > len || ulen < sizeof(*uh))
@@ -926,6 +929,7 @@
 
 short_packet:
 	NETDEBUG(if (net_ratelimit()) printk(KERN_DEBUG "UDP: short packet: %d/%d\n", ulen, len));
+no_header:
 	UDP_INC_STATS_BH(UdpInErrors);
 	kfree_skb(skb);
 	return(0);
diff -u --recursive --new-file v2.5.2/linux/net/ipv6/Config.in linux/net/ipv6/Config.in
--- v2.5.2/linux/net/ipv6/Config.in	Wed May 16 10:31:27 2001
+++ linux/net/ipv6/Config.in	Tue Jan 15 10:56:35 2002
@@ -1,11 +1,7 @@
 #
 # IPv6 configuration
 # 
-if [ "$CONFIG_NETLINK" = "y" ]; then
-   if [ "$CONFIG_RTNETLINK" = "n" ]; then
-      bool '    IPv6: routing messages via old netlink' CONFIG_IPV6_NETLINK
-   fi
-fi
+
 #bool '    IPv6: flow policy support' CONFIG_RT6_POLICY
 #bool '    IPv6: firewall support' CONFIG_IPV6_FIREWALL
 
diff -u --recursive --new-file v2.5.2/linux/net/ipv6/addrconf.c linux/net/ipv6/addrconf.c
--- v2.5.2/linux/net/ipv6/addrconf.c	Fri Sep  7 11:01:21 2001
+++ linux/net/ipv6/addrconf.c	Tue Jan 15 10:56:35 2002
@@ -6,7 +6,7 @@
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *	Alexey Kuznetsov	<kuznet@ms2.inr.ac.ru>
  *
- *	$Id: addrconf.c,v 1.68 2001/09/01 00:31:50 davem Exp $
+ *	$Id: addrconf.c,v 1.69 2001/10/31 21:55:54 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -1644,8 +1644,6 @@
 	mod_timer(&addr_chk_timer, jiffies + ADDR_CHECK_FREQUENCY);
 }
 
-#ifdef CONFIG_RTNETLINK
-
 static int
 inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
@@ -1806,13 +1804,11 @@
 	{ inet6_rtm_getroute,	inet6_dump_fib,		},
 	{ NULL,			NULL,			},
 };
-#endif
 
 static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
 {
-#ifdef CONFIG_RTNETLINK
 	inet6_ifa_notify(event ? : RTM_NEWADDR, ifp);
-#endif
+
 	switch (event) {
 	case RTM_NEWADDR:
 		ip6_rt_addr_add(&ifp->addr, ifp->idev->dev);
@@ -2021,9 +2017,7 @@
 	
 	addr_chk_timer.expires = jiffies + ADDR_CHECK_FREQUENCY;
 	add_timer(&addr_chk_timer);
-#ifdef CONFIG_RTNETLINK
 	rtnetlink_links[PF_INET6] = inet6_rtnetlink_table;
-#endif
 #ifdef CONFIG_SYSCTL
 	addrconf_sysctl.sysctl_header =
 		register_sysctl_table(addrconf_sysctl.addrconf_root_dir, 0);
@@ -2039,9 +2033,7 @@
  	struct inet6_ifaddr *ifa;
 	int i;
 
-#ifdef CONFIG_RTNETLINK
 	rtnetlink_links[PF_INET6] = NULL;
-#endif
 #ifdef CONFIG_SYSCTL
 	addrconf_sysctl_unregister(&ipv6_devconf_dflt);
 	addrconf_sysctl_unregister(&ipv6_devconf);
diff -u --recursive --new-file v2.5.2/linux/net/ipv6/ip6_fib.c linux/net/ipv6/ip6_fib.c
--- v2.5.2/linux/net/ipv6/ip6_fib.c	Thu Jun 14 14:16:58 2001
+++ linux/net/ipv6/ip6_fib.c	Tue Jan 15 10:56:35 2002
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: ip6_fib.c,v 1.24 2001/06/05 11:36:55 davem Exp $
+ *	$Id: ip6_fib.c,v 1.25 2001/10/31 21:55:55 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -466,9 +466,7 @@
 	*ins = rt;
 	rt->rt6i_node = fn;
 	atomic_inc(&rt->rt6i_ref);
-#ifdef CONFIG_RTNETLINK
 	inet6_rt_notify(RTM_NEWROUTE, rt);
-#endif
 	rt6_stats.fib_rt_entries++;
 
 	if ((fn->fn_flags & RTN_RTINFO) == 0) {
@@ -925,9 +923,7 @@
 		if (atomic_read(&rt->rt6i_ref) != 1) BUG();
 	}
 
-#ifdef CONFIG_RTNETLINK
 	inet6_rt_notify(RTM_DELROUTE, rt);
-#endif
 	rt6_release(rt);
 }
 
diff -u --recursive --new-file v2.5.2/linux/net/ipv6/ip6_fw.c linux/net/ipv6/ip6_fw.c
--- v2.5.2/linux/net/ipv6/ip6_fw.c	Tue Aug 31 11:23:03 1999
+++ linux/net/ipv6/ip6_fw.c	Tue Jan 15 10:56:35 2002
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: ip6_fw.c,v 1.15 1999/08/31 07:04:03 davem Exp $
+ *	$Id: ip6_fw.c,v 1.16 2001/10/31 08:17:58 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -379,16 +379,12 @@
 
 void __init ip6_fw_init(void)
 {
-#ifdef CONFIG_NETLINK
 	netlink_attach(NETLINK_IP6_FW, ip6_fw_msgrcv);
-#endif
 }
 
 #ifdef MODULE
 void cleanup_module(void)
 {
-#ifdef CONFIG_NETLINK
 	netlink_detach(NETLINK_IP6_FW);
-#endif
 }
 #endif
diff -u --recursive --new-file v2.5.2/linux/net/ipv6/ndisc.c linux/net/ipv6/ndisc.c
--- v2.5.2/linux/net/ipv6/ndisc.c	Mon Sep 10 07:57:00 2001
+++ linux/net/ipv6/ndisc.c	Tue Jan 15 10:56:35 2002
@@ -1207,81 +1207,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_PROC_FS
-#ifndef CONFIG_RTNETLINK
-static int ndisc_get_info(char *buffer, char **start, off_t offset, int length)
-{
-	int len=0;
-	off_t pos=0;
-	int size;
-	unsigned long now = jiffies;
-	int i;
-
-	for (i = 0; i <= NEIGH_HASHMASK; i++) {
-		struct neighbour *neigh;
-
-		read_lock_bh(&nd_tbl.lock);
-		for (neigh = nd_tbl.hash_buckets[i]; neigh; neigh = neigh->next) {
-			int j;
-
-			size = 0;
-			for (j=0; j<16; j++) {
-				sprintf(buffer+len+size, "%02x", neigh->primary_key[j]);
-				size += 2;
-			}
-
-			read_lock(&neigh->lock);
-			size += sprintf(buffer+len+size,
-				       " %02x %02x %02x %02x %08lx %08lx %08x %04x %04x %04x %8s ", i,
-				       128,
-				       neigh->type,
-				       neigh->nud_state,
-				       now - neigh->used,
-				       now - neigh->confirmed,
-				       neigh->parms->reachable_time,
-				       neigh->parms->gc_staletime,
-				       atomic_read(&neigh->refcnt) - 1,
-				       neigh->flags | (!neigh->hh ? 0 : (neigh->hh->hh_output==dev_queue_xmit ? 4 : 2)),
-				       neigh->dev->name);
-
-			if ((neigh->nud_state&NUD_VALID) && neigh->dev->addr_len) {
-				for (j=0; j < neigh->dev->addr_len; j++) {
-					sprintf(buffer+len+size, "%02x", neigh->ha[j]);
-					size += 2;
-				}
-			} else {
-                                size += sprintf(buffer+len+size, "000000000000");
-			}
-			read_unlock(&neigh->lock);
-			size += sprintf(buffer+len+size, "\n");
-			len += size;
-			pos += size;
-		  
-			if (pos <= offset)
-				len=0;
-			if (pos >= offset+length) {
-				read_unlock_bh(&nd_tbl.lock);
-				goto done;
-			}
-		}
-		read_unlock_bh(&nd_tbl.lock);
-	}
-
-done:
-
-	*start = buffer+len-(pos-offset);	/* Start of wanted data */
-	len = pos-offset;			/* Start slop */
-	if (len>length)
-		len = length;			/* Ending slop */
-	if (len<0)
-		len = 0;
-	return len;
-}
-
-#endif
-#endif	/* CONFIG_PROC_FS */
-
-
 int __init ndisc_init(struct net_proto_family *ops)
 {
 	struct sock *sk;
@@ -1319,11 +1244,6 @@
 	
 	neigh_table_init(&nd_tbl);
 
-#ifdef CONFIG_PROC_FS
-#ifndef CONFIG_RTNETLINK
-	proc_net_create("ndisc", 0, ndisc_get_info);
-#endif
-#endif
 #ifdef CONFIG_SYSCTL
 	neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, NET_IPV6_NEIGH, "ipv6");
 #endif
@@ -1333,11 +1253,6 @@
 
 void ndisc_cleanup(void)
 {
-#ifdef CONFIG_PROC_FS
-#ifndef CONFIG_RTNETLINK
-        proc_net_remove("ndisc");
-#endif
-#endif
 	neigh_table_clear(&nd_tbl);
 	sock_release(ndisc_socket);
 	ndisc_socket = NULL; /* For safety. */
diff -u --recursive --new-file v2.5.2/linux/net/ipv6/netfilter/Config.in linux/net/ipv6/netfilter/Config.in
--- v2.5.2/linux/net/ipv6/netfilter/Config.in	Tue Oct 30 15:08:12 2001
+++ linux/net/ipv6/netfilter/Config.in	Tue Jan 15 10:56:35 2002
@@ -9,7 +9,7 @@
 #  dep_tristate '  FTP protocol support' CONFIG_IP6_NF_FTP $CONFIG_IP6_NF_CONNTRACK
 #fi
 
-#if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_NETLINK" = "y" ]; then
+#if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
 #  tristate 'Userspace queueing via NETLINK (EXPERIMENTAL)' CONFIG_IP6_NF_QUEUE
 #fi
 tristate 'IP6 tables support (required for filtering/masq/NAT)' CONFIG_IP6_NF_IPTABLES
diff -u --recursive --new-file v2.5.2/linux/net/ipv6/route.c linux/net/ipv6/route.c
--- v2.5.2/linux/net/ipv6/route.c	Thu Sep 20 14:12:56 2001
+++ linux/net/ipv6/route.c	Tue Jan 15 10:56:35 2002
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: route.c,v 1.55 2001/09/18 22:29:10 davem Exp $
+ *	$Id: route.c,v 1.56 2001/10/31 21:55:55 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -1407,8 +1407,6 @@
 	read_unlock_bh(&rt6_lock);
 }
 
-#ifdef CONFIG_RTNETLINK
-
 static int inet6_rtm_to_rtmsg(struct rtmsg *r, struct rtattr **rta,
 			      struct in6_rtmsg *rtmsg)
 {
@@ -1740,8 +1738,6 @@
 	NETLINK_CB(skb).dst_groups = RTMGRP_IPV6_ROUTE;
 	netlink_broadcast(rtnl, skb, 0, RTMGRP_IPV6_ROUTE, gfp_any());
 }
-
-#endif
 
 /*
  *	/proc
diff -u --recursive --new-file v2.5.2/linux/net/netlink/netlink_dev.c linux/net/netlink/netlink_dev.c
--- v2.5.2/linux/net/netlink/netlink_dev.c	Mon Jan 14 18:25:11 2002
+++ linux/net/netlink/netlink_dev.c	Tue Jan 15 10:56:35 2002
@@ -195,11 +195,13 @@
 	/*  Someone tell me the official names for the uppercase ones  */
 	make_devfs_entries ("route", 0);
 	make_devfs_entries ("skip", 1);
-	make_devfs_entries ("USERSOCK", 2);
+	make_devfs_entries ("usersock", 2);
 	make_devfs_entries ("fwmonitor", 3);
-	make_devfs_entries ("ARPD", 8);
-	make_devfs_entries ("ROUTE6", 11);
-	make_devfs_entries ("IP6_FW", 13);
+	make_devfs_entries ("tcpdiag", 4);
+	make_devfs_entries ("arpd", 8);
+	make_devfs_entries ("route6", 11);
+	make_devfs_entries ("ip6_fw", 13);
+	make_devfs_entries ("dnrtmsg", 13);
 	devfs_register_series (devfs_handle, "tap%u", 16, DEVFS_FL_DEFAULT,
 			       NETLINK_MAJOR, 16,
 			       S_IFCHR | S_IRUSR | S_IWUSR,
diff -u --recursive --new-file v2.5.2/linux/net/netsyms.c linux/net/netsyms.c
--- v2.5.2/linux/net/netsyms.c	Mon Nov  5 09:46:12 2001
+++ linux/net/netsyms.c	Tue Jan 15 10:56:35 2002
@@ -116,6 +116,7 @@
 EXPORT_SYMBOL(sk_free);
 EXPORT_SYMBOL(sock_wake_async);
 EXPORT_SYMBOL(sock_alloc_send_skb);
+EXPORT_SYMBOL(sock_alloc_send_pskb);
 EXPORT_SYMBOL(sock_init_data);
 EXPORT_SYMBOL(sock_no_release);
 EXPORT_SYMBOL(sock_no_bind);
@@ -406,7 +407,6 @@
 
 #endif
 
-#ifdef CONFIG_NETLINK
 EXPORT_SYMBOL(netlink_set_err);
 EXPORT_SYMBOL(netlink_broadcast);
 EXPORT_SYMBOL(netlink_unicast);
@@ -418,9 +418,7 @@
 EXPORT_SYMBOL(netlink_detach);
 EXPORT_SYMBOL(netlink_post);
 #endif
-#endif
 
-#ifdef CONFIG_RTNETLINK
 EXPORT_SYMBOL(rtattr_parse);
 EXPORT_SYMBOL(rtnetlink_links);
 EXPORT_SYMBOL(__rta_fill);
@@ -430,7 +428,6 @@
 EXPORT_SYMBOL(neigh_delete);
 EXPORT_SYMBOL(neigh_add);
 EXPORT_SYMBOL(neigh_dump_info);
-#endif
 
 EXPORT_SYMBOL(dev_set_allmulti);
 EXPORT_SYMBOL(dev_set_promiscuity);
@@ -553,9 +550,7 @@
 EXPORT_SYMBOL(tcf_police);
 EXPORT_SYMBOL(tcf_police_locate);
 EXPORT_SYMBOL(tcf_police_destroy);
-#ifdef CONFIG_RTNETLINK
 EXPORT_SYMBOL(tcf_police_dump);
-#endif
 #endif
 #endif
 #ifdef CONFIG_NET_CLS
diff -u --recursive --new-file v2.5.2/linux/net/packet/af_packet.c linux/net/packet/af_packet.c
--- v2.5.2/linux/net/packet/af_packet.c	Mon Jan 14 18:25:11 2002
+++ linux/net/packet/af_packet.c	Tue Jan 15 10:56:36 2002
@@ -5,7 +5,7 @@
  *
  *		PACKET - implements raw packet sockets.
  *
- * Version:	$Id: af_packet.c,v 1.58 2001/11/28 21:02:10 davem Exp $
+ * Version:	$Id: af_packet.c,v 1.59 2001/12/21 04:56:17 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1763,7 +1763,7 @@
 	start = vma->vm_start;
 	err = -EAGAIN;
 	for (i=0; i<po->pg_vec_len; i++) {
-		if (remap_page_range(start, __pa(po->pg_vec[i]),
+		if (remap_page_range(vma, start, __pa(po->pg_vec[i]),
 				     po->pg_vec_pages*PAGE_SIZE,
 				     vma->vm_page_prot))
 			goto out;
diff -u --recursive --new-file v2.5.2/linux/net/sched/Config.in linux/net/sched/Config.in
--- v2.5.2/linux/net/sched/Config.in	Fri Jan 14 19:18:53 2000
+++ linux/net/sched/Config.in	Tue Jan 15 10:56:35 2002
@@ -1,8 +1,6 @@
 #
 # Traffic control configuration.
 # 
-define_bool CONFIG_NETLINK y
-define_bool CONFIG_RTNETLINK y	
 tristate '  CBQ packet scheduler' CONFIG_NET_SCH_CBQ
 tristate '  CSZ packet scheduler' CONFIG_NET_SCH_CSZ
 #tristate '  H-PFQ packet scheduler' CONFIG_NET_SCH_HPFQ
diff -u --recursive --new-file v2.5.2/linux/net/sched/cls_api.c linux/net/sched/cls_api.c
--- v2.5.2/linux/net/sched/cls_api.c	Fri Jan  7 16:57:13 2000
+++ linux/net/sched/cls_api.c	Tue Jan 15 10:56:35 2002
@@ -97,8 +97,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_RTNETLINK
-
 static int tfilter_notify(struct sk_buff *oskb, struct nlmsghdr *n,
 			  struct tcf_proto *tp, unsigned long fh, int event);
 
@@ -430,12 +428,9 @@
 	return skb->len;
 }
 
-#endif
-
 
 int __init tc_filter_init(void)
 {
-#ifdef CONFIG_RTNETLINK
 	struct rtnetlink_link *link_p = rtnetlink_links[PF_UNSPEC];
 
 	/* Setup rtnetlink links. It is made here to avoid
@@ -448,7 +443,6 @@
 		link_p[RTM_GETTFILTER-RTM_BASE].doit = tc_ctl_tfilter;
 		link_p[RTM_GETTFILTER-RTM_BASE].dumpit = tc_dump_tfilter;
 	}
-#endif
 #define INIT_TC_FILTER(name) { \
           extern struct tcf_proto_ops cls_##name##_ops; \
           register_tcf_proto_ops(&cls_##name##_ops); \
diff -u --recursive --new-file v2.5.2/linux/net/sched/cls_fw.c linux/net/sched/cls_fw.c
--- v2.5.2/linux/net/sched/cls_fw.c	Sun Sep 30 12:26:09 2001
+++ linux/net/sched/cls_fw.c	Tue Jan 15 10:56:35 2002
@@ -299,7 +299,6 @@
 	}
 }
 
-#ifdef CONFIG_RTNETLINK
 static int fw_dump(struct tcf_proto *tp, unsigned long fh,
 		   struct sk_buff *skb, struct tcmsg *t)
 {
@@ -350,8 +349,6 @@
 	skb_trim(skb, b - skb->data);
 	return -1;
 }
-#endif
-
 
 struct tcf_proto_ops cls_fw_ops = {
 	NULL,
@@ -365,11 +362,7 @@
 	fw_change,
 	fw_delete,
 	fw_walk,
-#ifdef CONFIG_RTNETLINK
 	fw_dump
-#else
-	NULL
-#endif
 };
 
 #ifdef MODULE
diff -u --recursive --new-file v2.5.2/linux/net/sched/cls_route.c linux/net/sched/cls_route.c
--- v2.5.2/linux/net/sched/cls_route.c	Sun Sep 30 12:26:09 2001
+++ linux/net/sched/cls_route.c	Tue Jan 15 10:56:35 2002
@@ -550,7 +550,6 @@
 	}
 }
 
-#ifdef CONFIG_RTNETLINK
 static int route4_dump(struct tcf_proto *tp, unsigned long fh,
 		       struct sk_buff *skb, struct tcmsg *t)
 {
@@ -606,7 +605,6 @@
 	skb_trim(skb, b - skb->data);
 	return -1;
 }
-#endif
 
 struct tcf_proto_ops cls_route4_ops = {
 	NULL,
@@ -620,11 +618,7 @@
 	route4_change,
 	route4_delete,
 	route4_walk,
-#ifdef CONFIG_RTNETLINK
 	route4_dump
-#else
-	NULL
-#endif
 };
 
 #ifdef MODULE
diff -u --recursive --new-file v2.5.2/linux/net/sched/cls_rsvp.h linux/net/sched/cls_rsvp.h
--- v2.5.2/linux/net/sched/cls_rsvp.h	Mon Dec 11 13:30:43 2000
+++ linux/net/sched/cls_rsvp.h	Tue Jan 15 10:56:35 2002
@@ -615,7 +615,6 @@
 	}
 }
 
-#ifdef CONFIG_RTNETLINK
 static int rsvp_dump(struct tcf_proto *tp, unsigned long fh,
 		     struct sk_buff *skb, struct tcmsg *t)
 {
@@ -672,7 +671,6 @@
 	skb_trim(skb, b - skb->data);
 	return -1;
 }
-#endif
 
 struct tcf_proto_ops RSVP_OPS = {
 	NULL,
@@ -686,11 +684,7 @@
 	rsvp_change,
 	rsvp_delete,
 	rsvp_walk,
-#ifdef CONFIG_RTNETLINK
 	rsvp_dump
-#else
-	NULL
-#endif
 };
 
 #ifdef MODULE
diff -u --recursive --new-file v2.5.2/linux/net/sched/cls_tcindex.c linux/net/sched/cls_tcindex.c
--- v2.5.2/linux/net/sched/cls_tcindex.c	Sun Sep 30 12:26:09 2001
+++ linux/net/sched/cls_tcindex.c	Tue Jan 15 10:56:35 2002
@@ -421,8 +421,6 @@
 }
 
 
-#ifdef CONFIG_RTNETLINK
-
 static int tcindex_dump(struct tcf_proto *tp, unsigned long fh,
     struct sk_buff *skb, struct tcmsg *t)
 {
@@ -481,9 +479,6 @@
 	return -1;
 }
 
-#endif
-
-
 struct tcf_proto_ops cls_tcindex_ops = {
 	NULL,
 	"tcindex",
@@ -496,11 +491,7 @@
 	tcindex_change,
 	tcindex_delete,
 	tcindex_walk,
-#ifdef CONFIG_RTNETLINK
 	tcindex_dump
-#else
-	NULL
-#endif
 };
 
 
diff -u --recursive --new-file v2.5.2/linux/net/sched/cls_u32.c linux/net/sched/cls_u32.c
--- v2.5.2/linux/net/sched/cls_u32.c	Sun Sep 30 12:26:09 2001
+++ linux/net/sched/cls_u32.c	Tue Jan 15 10:56:35 2002
@@ -635,7 +635,6 @@
 	}
 }
 
-#ifdef CONFIG_RTNETLINK
 static int u32_dump(struct tcf_proto *tp, unsigned long fh,
 		     struct sk_buff *skb, struct tcmsg *t)
 {
@@ -694,7 +693,6 @@
 	skb_trim(skb, b - skb->data);
 	return -1;
 }
-#endif
 
 struct tcf_proto_ops cls_u32_ops = {
 	NULL,
@@ -708,11 +706,7 @@
 	u32_change,
 	u32_delete,
 	u32_walk,
-#ifdef CONFIG_RTNETLINK
 	u32_dump
-#else
-	NULL
-#endif
 };
 
 #ifdef MODULE
diff -u --recursive --new-file v2.5.2/linux/net/sched/police.c linux/net/sched/police.c
--- v2.5.2/linux/net/sched/police.c	Mon Aug 23 10:01:02 1999
+++ linux/net/sched/police.c	Tue Jan 15 10:56:35 2002
@@ -219,7 +219,6 @@
 	return p->action;
 }
 
-#ifdef CONFIG_RTNETLINK
 int tcf_police_dump(struct sk_buff *skb, struct tcf_police *p)
 {
 	unsigned char	 *b = skb->tail;
@@ -250,5 +249,3 @@
 	skb_trim(skb, b - skb->data);
 	return -1;
 }
-#endif
-
diff -u --recursive --new-file v2.5.2/linux/net/sched/sch_api.c linux/net/sched/sch_api.c
--- v2.5.2/linux/net/sched/sch_api.c	Fri Nov  9 14:12:54 2001
+++ linux/net/sched/sch_api.c	Tue Jan 15 10:56:35 2002
@@ -41,12 +41,10 @@
 #include <asm/system.h>
 #include <asm/bitops.h>
 
-#ifdef CONFIG_RTNETLINK
 static int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n, u32 clid,
 			struct Qdisc *old, struct Qdisc *new);
 static int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n,
 			 struct Qdisc *q, unsigned long cl, int event);
-#endif
 
 /*
 
@@ -379,8 +377,6 @@
 	return err;
 }
 
-#ifdef CONFIG_RTNETLINK
-
 /*
    Allocate and initialize new qdisc.
 
@@ -1055,7 +1051,6 @@
 	dev_put(dev);
 	return skb->len;
 }
-#endif
 
 int psched_us_per_tick = 1;
 int psched_tick_per_us = 1;
@@ -1169,9 +1164,7 @@
 
 int __init pktsched_init(void)
 {
-#ifdef CONFIG_RTNETLINK
 	struct rtnetlink_link *link_p;
-#endif
 
 #if PSCHED_CLOCK_SOURCE == PSCHED_CPU
 	if (psched_calibrate_clock() < 0)
@@ -1184,7 +1177,6 @@
 #endif
 #endif
 
-#ifdef CONFIG_RTNETLINK
 	link_p = rtnetlink_links[PF_UNSPEC];
 
 	/* Setup rtnetlink links. It is made here to avoid
@@ -1201,7 +1193,6 @@
 		link_p[RTM_GETTCLASS-RTM_BASE].doit = tc_ctl_tclass;
 		link_p[RTM_GETTCLASS-RTM_BASE].dumpit = tc_dump_tclass;
 	}
-#endif
 
 #define INIT_QDISC(name) { \
           extern struct Qdisc_ops name##_qdisc_ops; \
diff -u --recursive --new-file v2.5.2/linux/net/sched/sch_atm.c linux/net/sched/sch_atm.c
--- v2.5.2/linux/net/sched/sch_atm.c	Fri Feb  9 11:34:13 2001
+++ linux/net/sched/sch_atm.c	Tue Jan 15 10:56:35 2002
@@ -619,8 +619,6 @@
 }
 
 
-#ifdef CONFIG_RTNETLINK
-
 static int atm_tc_dump_class(struct Qdisc *sch, unsigned long cl,
     struct sk_buff *skb, struct tcmsg *tcm)
 {
@@ -668,9 +666,6 @@
 	return 0;
 }
 
-#endif
-
-
 static struct Qdisc_class_ops atm_class_ops =
 {
 	atm_tc_graft,			/* graft */
@@ -685,9 +680,7 @@
 	atm_tc_bind_filter,		/* bind_tcf */
 	atm_tc_put,			/* unbind_tcf */
 
-#ifdef CONFIG_RTNETLINK
 	atm_tc_dump_class,		/* dump */
-#endif
 };
 
 struct Qdisc_ops atm_qdisc_ops =
@@ -707,9 +700,7 @@
 	atm_tc_destroy,			/* destroy */
 	NULL,				/* change */
 
-#ifdef CONFIG_RTNETLINK
 	atm_tc_dump			/* dump */
-#endif
 };
 
 
diff -u --recursive --new-file v2.5.2/linux/net/sched/sch_cbq.c linux/net/sched/sch_cbq.c
--- v2.5.2/linux/net/sched/sch_cbq.c	Sun Sep 30 12:26:09 2001
+++ linux/net/sched/sch_cbq.c	Tue Jan 15 10:56:35 2002
@@ -1457,8 +1457,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_RTNETLINK
-
 static __inline__ int cbq_dump_rate(struct sk_buff *skb, struct cbq_class *cl)
 {
 	unsigned char	 *b = skb->tail;
@@ -1658,8 +1656,6 @@
 	return -1;
 }
 
-#endif
-
 static int cbq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
 		     struct Qdisc **old)
 {
@@ -2082,9 +2078,7 @@
 	cbq_bind_filter,
 	cbq_unbind_filter,
 
-#ifdef CONFIG_RTNETLINK
 	cbq_dump_class,
-#endif
 };
 
 struct Qdisc_ops cbq_qdisc_ops =
@@ -2104,9 +2098,7 @@
 	cbq_destroy,
 	NULL /* cbq_change */,
 
-#ifdef CONFIG_RTNETLINK
 	cbq_dump,
-#endif
 };
 
 #ifdef MODULE
diff -u --recursive --new-file v2.5.2/linux/net/sched/sch_csz.c linux/net/sched/sch_csz.c
--- v2.5.2/linux/net/sched/sch_csz.c	Sun Sep 30 12:26:09 2001
+++ linux/net/sched/sch_csz.c	Tue Jan 15 10:56:35 2002
@@ -795,7 +795,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_RTNETLINK
 static int csz_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
 	struct csz_sched_data *q = (struct csz_sched_data *)sch->data;
@@ -817,8 +816,6 @@
 	skb_trim(skb, b - skb->data);
 	return -1;
 }
-#endif
-
 
 static int csz_graft(struct Qdisc *sch, unsigned long cl, struct Qdisc *new,
 		     struct Qdisc **old)
@@ -932,7 +929,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_RTNETLINK
 static int csz_dump_class(struct Qdisc *sch, unsigned long cl, struct sk_buff *skb, struct tcmsg *tcm)
 {
 	struct csz_sched_data *q = (struct csz_sched_data *)sch->data;
@@ -978,7 +974,6 @@
 	skb_trim(skb, b - skb->data);
 	return -1;
 }
-#endif
 
 static void csz_walk(struct Qdisc *sch, struct qdisc_walker *arg)
 {
@@ -1030,9 +1025,7 @@
 	csz_bind,
 	csz_put,
 
-#ifdef CONFIG_RTNETLINK
 	csz_dump_class,
-#endif
 };
 
 struct Qdisc_ops csz_qdisc_ops =
@@ -1052,9 +1045,7 @@
 	csz_destroy,
 	NULL /* csz_change */,
 
-#ifdef CONFIG_RTNETLINK
 	csz_dump,
-#endif
 };
 
 
diff -u --recursive --new-file v2.5.2/linux/net/sched/sch_dsmark.c linux/net/sched/sch_dsmark.c
--- v2.5.2/linux/net/sched/sch_dsmark.c	Sun Sep 30 12:26:09 2001
+++ linux/net/sched/sch_dsmark.c	Tue Jan 15 10:56:35 2002
@@ -385,8 +385,6 @@
 }
 
 
-#ifdef CONFIG_RTNETLINK
-
 static int dsmark_dump_class(struct Qdisc *sch, unsigned long cl,
     struct sk_buff *skb, struct tcmsg *tcm)
 {
@@ -434,9 +432,6 @@
 	return -1;
 }
 
-#endif
-
-
 static struct Qdisc_class_ops dsmark_class_ops =
 {
 	dsmark_graft,			/* graft */
@@ -451,9 +446,7 @@
 	dsmark_bind_filter,		/* bind_tcf */
 	dsmark_put,			/* unbind_tcf */
 
-#ifdef CONFIG_RTNETLINK
 	dsmark_dump_class,		/* dump */
-#endif
 };
 
 struct Qdisc_ops dsmark_qdisc_ops =
@@ -473,9 +466,7 @@
 	dsmark_destroy,			/* destroy */
 	NULL,				/* change */
 
-#ifdef CONFIG_RTNETLINK
 	dsmark_dump			/* dump */
-#endif
 };
 
 #ifdef MODULE
diff -u --recursive --new-file v2.5.2/linux/net/sched/sch_fifo.c linux/net/sched/sch_fifo.c
--- v2.5.2/linux/net/sched/sch_fifo.c	Mon Aug 23 10:01:02 1999
+++ linux/net/sched/sch_fifo.c	Tue Jan 15 10:56:35 2002
@@ -152,7 +152,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_RTNETLINK
 static int fifo_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
 	struct fifo_sched_data *q = (void*)sch->data;
@@ -168,7 +167,6 @@
 	skb_trim(skb, b - skb->data);
 	return -1;
 }
-#endif
 
 struct Qdisc_ops pfifo_qdisc_ops =
 {
@@ -187,9 +185,7 @@
 	NULL,
 	fifo_init,
 
-#ifdef CONFIG_RTNETLINK
 	fifo_dump,
-#endif
 };
 
 struct Qdisc_ops bfifo_qdisc_ops =
@@ -208,7 +204,5 @@
 	fifo_reset,
 	NULL,
 	fifo_init,
-#ifdef CONFIG_RTNETLINK
 	fifo_dump,
-#endif
 };
diff -u --recursive --new-file v2.5.2/linux/net/sched/sch_gred.c linux/net/sched/sch_gred.c
--- v2.5.2/linux/net/sched/sch_gred.c	Sun Sep 30 12:26:09 2001
+++ linux/net/sched/sch_gred.c	Tue Jan 15 10:56:35 2002
@@ -494,7 +494,6 @@
 	return -EINVAL;
 }
 
-#ifdef CONFIG_RTNETLINK
 static int gred_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
 	unsigned long qave;
@@ -587,7 +586,6 @@
 	skb_trim(skb, b - skb->data);
 	return -1;
 }
-#endif
 
 static void gred_destroy(struct Qdisc *sch)
 {
@@ -615,9 +613,7 @@
 	gred_reset,
 	gred_destroy,
 	gred_change, /* change */
-#ifdef CONFIG_RTNETLINK
 	gred_dump,
-#endif
 };
 
 
diff -u --recursive --new-file v2.5.2/linux/net/sched/sch_ingress.c linux/net/sched/sch_ingress.c
--- v2.5.2/linux/net/sched/sch_ingress.c	Sun Sep 30 12:26:09 2001
+++ linux/net/sched/sch_ingress.c	Tue Jan 15 10:56:35 2002
@@ -304,9 +304,6 @@
 }
 
 
-#ifdef CONFIG_RTNETLINK
-
-
 static int ingress_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
 	unsigned char *b = skb->tail;
@@ -322,9 +319,6 @@
 	return -1;
 }
 
-#endif
-
-
 static struct Qdisc_class_ops ingress_class_ops =
 {
 	ingress_graft,			/* graft */
@@ -339,9 +333,7 @@
 	ingress_bind_filter,		/* bind_tcf */
 	ingress_put,			/* unbind_tcf */
 
-#ifdef CONFIG_RTNETLINK
 	NULL,		/* dump */
-#endif
 };
 
 struct Qdisc_ops ingress_qdisc_ops =
@@ -361,9 +353,7 @@
 	ingress_destroy,		/* destroy */
 	NULL,				/* change */
 
-#ifdef CONFIG_RTNETLINK
 	ingress_dump,			/* dump */
-#endif
 };
 
 #ifdef MODULE
diff -u --recursive --new-file v2.5.2/linux/net/sched/sch_prio.c linux/net/sched/sch_prio.c
--- v2.5.2/linux/net/sched/sch_prio.c	Sun Sep 30 12:26:09 2001
+++ linux/net/sched/sch_prio.c	Tue Jan 15 10:56:35 2002
@@ -231,7 +231,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_RTNETLINK
 static int prio_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
 	struct prio_sched_data *q = (struct prio_sched_data *)sch->data;
@@ -247,7 +246,6 @@
 	skb_trim(skb, b - skb->data);
 	return -1;
 }
-#endif
 
 static int prio_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
 		      struct Qdisc **old)
@@ -322,7 +320,6 @@
 }
 
 
-#ifdef CONFIG_RTNETLINK
 static int prio_dump_class(struct Qdisc *sch, unsigned long cl, struct sk_buff *skb,
 			   struct tcmsg *tcm)
 {
@@ -334,7 +331,6 @@
 		tcm->tcm_info = q->queues[cl-1]->handle;
 	return 0;
 }
-#endif
 
 static void prio_walk(struct Qdisc *sch, struct qdisc_walker *arg)
 {
@@ -381,9 +377,7 @@
 	prio_bind,
 	prio_put,
 
-#ifdef CONFIG_RTNETLINK
 	prio_dump_class,
-#endif
 };
 
 struct Qdisc_ops prio_qdisc_ops =
@@ -403,9 +397,7 @@
 	prio_destroy,
 	prio_tune,
 
-#ifdef CONFIG_RTNETLINK
 	prio_dump,
-#endif
 };
 
 #ifdef MODULE
diff -u --recursive --new-file v2.5.2/linux/net/sched/sch_red.c linux/net/sched/sch_red.c
--- v2.5.2/linux/net/sched/sch_red.c	Sun Sep 30 12:26:09 2001
+++ linux/net/sched/sch_red.c	Tue Jan 15 10:56:35 2002
@@ -418,7 +418,6 @@
 }
 
 
-#ifdef CONFIG_RTNETLINK
 int red_copy_xstats(struct sk_buff *skb, struct tc_red_xstats *st)
 {
         RTA_PUT(skb, TCA_XSTATS, sizeof(*st), st);
@@ -456,7 +455,6 @@
 	skb_trim(skb, b - skb->data);
 	return -1;
 }
-#endif
 
 static void red_destroy(struct Qdisc *sch)
 {
@@ -480,9 +478,7 @@
 	red_destroy,
 	red_change,
 
-#ifdef CONFIG_RTNETLINK
 	red_dump,
-#endif
 };
 
 
diff -u --recursive --new-file v2.5.2/linux/net/sched/sch_sfq.c linux/net/sched/sch_sfq.c
--- v2.5.2/linux/net/sched/sch_sfq.c	Sun Sep 30 12:26:09 2001
+++ linux/net/sched/sch_sfq.c	Tue Jan 15 10:56:35 2002
@@ -439,7 +439,6 @@
 	MOD_DEC_USE_COUNT;
 }
 
-#ifdef CONFIG_RTNETLINK
 static int sfq_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
 	struct sfq_sched_data *q = (struct sfq_sched_data *)sch->data;
@@ -461,7 +460,6 @@
 	skb_trim(skb, b - skb->data);
 	return -1;
 }
-#endif
 
 struct Qdisc_ops sfq_qdisc_ops =
 {
@@ -480,9 +478,7 @@
 	sfq_destroy,
 	NULL, /* sfq_change */
 
-#ifdef CONFIG_RTNETLINK
 	sfq_dump,
-#endif
 };
 
 #ifdef MODULE
diff -u --recursive --new-file v2.5.2/linux/net/sched/sch_tbf.c linux/net/sched/sch_tbf.c
--- v2.5.2/linux/net/sched/sch_tbf.c	Sun Sep 30 12:26:09 2001
+++ linux/net/sched/sch_tbf.c	Tue Jan 15 10:56:35 2002
@@ -363,7 +363,6 @@
 	MOD_DEC_USE_COUNT;
 }
 
-#ifdef CONFIG_RTNETLINK
 static int tbf_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
 	struct tbf_sched_data *q = (struct tbf_sched_data *)sch->data;
@@ -391,7 +390,6 @@
 	skb_trim(skb, b - skb->data);
 	return -1;
 }
-#endif
 
 struct Qdisc_ops tbf_qdisc_ops =
 {
@@ -410,9 +408,7 @@
 	tbf_destroy,
 	tbf_change,
 
-#ifdef CONFIG_RTNETLINK
 	tbf_dump,
-#endif
 };
 
 
diff -u --recursive --new-file v2.5.2/linux/net/socket.c linux/net/socket.c
--- v2.5.2/linux/net/socket.c	Mon Jan 14 18:25:11 2002
+++ linux/net/socket.c	Fri Jan 18 16:00:26 2002
@@ -67,6 +67,8 @@
 #include <linux/netdevice.h>
 #include <linux/proc_fs.h>
 #include <linux/wanrouter.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
 #include <linux/init.h>
 #include <linux/poll.h>
 #include <linux/cache.h>
@@ -79,11 +81,7 @@
 
 #include <asm/uaccess.h>
 
-#include <linux/inet.h>
-#include <net/ip.h>
 #include <net/sock.h>
-#include <net/tcp.h>
-#include <net/udp.h>
 #include <net/scm.h>
 #include <linux/netfilter.h>
 
@@ -280,16 +278,17 @@
 
 static struct super_block * sockfs_read_super(struct super_block *sb, void *data, int silent)
 {
-	struct inode *root = new_inode(sb);
+	struct inode *root;
+	sb->s_blocksize = 1024;
+	sb->s_blocksize_bits = 10;
+	sb->s_magic = SOCKFS_MAGIC;
+	sb->s_op	= &sockfs_ops;
+	root = new_inode(sb);
 	if (!root)
 		return NULL;
 	root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
 	root->i_uid = root->i_gid = 0;
 	root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
-	sb->s_blocksize = 1024;
-	sb->s_blocksize_bits = 10;
-	sb->s_magic = SOCKFS_MAGIC;
-	sb->s_op	= &sockfs_ops;
 	sb->s_root = d_alloc(NULL, &(const struct qstr) { "socket:", 7, 0 });
 	if (!sb->s_root) {
 		iput(root);
@@ -439,11 +438,11 @@
 	struct inode * inode;
 	struct socket * sock;
 
-	inode = get_empty_inode();
+	inode = new_inode(sock_mnt->mnt_sb);
 	if (!inode)
 		return NULL;
 
-	inode->i_sb = sock_mnt->mnt_sb;
+	inode->i_dev = NODEV;
 	sock = socki_lookup(inode);
 
 	inode->i_mode = S_IFSOCK|S_IRWXUGO;
@@ -1723,7 +1722,7 @@
 	 * The netlink device handler may be needed early.
 	 */
 
-#ifdef  CONFIG_RTNETLINK
+#ifdef CONFIG_NET
 	rtnetlink_init();
 #endif
 #ifdef CONFIG_NETLINK_DEV
diff -u --recursive --new-file v2.5.2/linux/net/sunrpc/sched.c linux/net/sunrpc/sched.c
--- v2.5.2/linux/net/sunrpc/sched.c	Mon Jan 14 18:25:11 2002
+++ linux/net/sunrpc/sched.c	Tue Jan 15 13:53:51 2002
@@ -721,7 +721,7 @@
 
 		__rpc_execute(task);
 
-		if (++count >= 200 || current->need_resched) {
+		if (++count >= 200 || need_resched()) {
 			count = 0;
 			schedule();
 		}
diff -u --recursive --new-file v2.5.2/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v2.5.2/linux/net/unix/af_unix.c	Mon Jan 14 18:25:11 2002
+++ linux/net/unix/af_unix.c	Tue Jan 15 10:56:35 2002
@@ -8,7 +8,7 @@
  *		as published by the Free Software Foundation; either version
  *		2 of the License, or (at your option) any later version.
  *
- * Version:	$Id: af_unix.c,v 1.123 2001/09/19 04:50:32 davem Exp $
+ * Version:	$Id: af_unix.c,v 1.131 2002/01/14 07:08:27 davem Exp $
  *
  * Fixes:
  *		Linus Torvalds	:	Assorted bug cures.
@@ -101,13 +101,14 @@
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
 #include <net/sock.h>
-#include <net/tcp.h>
+#include <linux/tcp.h>
 #include <net/af_unix.h>
 #include <linux/proc_fs.h>
 #include <net/scm.h>
 #include <linux/init.h>
 #include <linux/poll.h>
 #include <linux/smp_lock.h>
+#include <linux/rtnetlink.h>
 
 #include <asm/checksum.h>
 
@@ -483,7 +484,7 @@
 	sk->protinfo.af_unix.dentry=NULL;
 	sk->protinfo.af_unix.mnt=NULL;
 	sk->protinfo.af_unix.lock = RW_LOCK_UNLOCKED;
-	atomic_set(&sk->protinfo.af_unix.inflight, 0);
+	atomic_set(&sk->protinfo.af_unix.inflight, sock ? 0 : -1);
 	init_MUTEX(&sk->protinfo.af_unix.readsem);/* single task reading lock */
 	init_waitqueue_head(&sk->protinfo.af_unix.peer_wait);
 	sk->protinfo.af_unix.list=NULL;
@@ -988,7 +989,12 @@
 	unix_state_wunlock(sk);
 
 	/* take ten and and send info to listening sock */
-	skb_queue_tail(&other->receive_queue,skb);
+	spin_lock(&other->receive_queue.lock);
+	__skb_queue_tail(&other->receive_queue,skb);
+	/* Undo artificially decreased inflight after embrion
+	 * is installed to listening socket. */
+	atomic_inc(&newsk->protinfo.af_unix.inflight);
+	spin_unlock(&other->receive_queue.lock);
 	unix_state_runlock(other);
 	other->data_ready(other, 0);
 	sock_put(other);
@@ -1051,8 +1057,12 @@
 	 */
 
 	skb = skb_recv_datagram(sk, 0, flags&O_NONBLOCK, &err);
-	if (!skb)
+	if (!skb) {
+		/* This means receive shutdown. */
+		if (err == 0)
+			err = -EINVAL;
 		goto out;
+	}
 
 	tsk = skb->sk;
 	skb_free_datagram(sk, skb);
diff -u --recursive --new-file v2.5.2/linux/net/unix/garbage.c linux/net/unix/garbage.c
--- v2.5.2/linux/net/unix/garbage.c	Fri Jun 29 19:38:26 2001
+++ linux/net/unix/garbage.c	Tue Jan 15 10:56:35 2002
@@ -76,9 +76,9 @@
 #include <linux/netdevice.h>
 #include <linux/file.h>
 #include <linux/proc_fs.h>
+#include <linux/tcp.h>
 
 #include <net/sock.h>
-#include <net/tcp.h>
 #include <net/af_unix.h>
 #include <net/scm.h>
 
@@ -205,12 +205,21 @@
 
 	forall_unix_sockets(i, s)
 	{
+		int open_count = 0;
+
 		/*
 		 *	If all instances of the descriptor are not
 		 *	in flight we are in use.
+		 *
+		 *	Special case: when socket s is embrion, it may be
+		 *	hashed but still not in queue of listening socket.
+		 *	In this case (see unix_create1()) we set artificial
+		 *	negative inflight counter to close race window.
+		 *	It is trick of course and dirty one.
 		 */
-		if(s->socket && s->socket->file &&
-		   file_count(s->socket->file) > atomic_read(&s->protinfo.af_unix.inflight))
+		if(s->socket && s->socket->file)
+			open_count = file_count(s->socket->file);
+		if (open_count > atomic_read(&s->protinfo.af_unix.inflight))
 			maybe_unmark_and_push(s);
 	}
 
